Migrating COM/DCOM Applications in Microsoft .NET Framework
In the current Internet scenario, various classic applications run on multiple networks. These applications could have been written using different languages like Visual Basic, Visual C++. For example, a retail organization would have different systems, such as an inventory management system, a bill of material systems, and a general ledger system, all implemented using various technologies available for application development. These systems need to be integrated to form a higher-level enterprise information system for an organization.
In the current Internet scenario, various classic applications run on multiple networks. These applications could have been written using different languages like Visual Basic, Visual C++. For example, a retail organization would have different systems, such as an inventory management system, a bill of material systems, and a general ledger system, all implemented using various technologies available for application development. These systems need to be integrated to form a higher-level enterprise information system for an organization. To do so, application developers had to use technologies such as Microsoft Distributed Component Object Model (DCOM), Component Object Model and so on. However, these distributed technologies are very tightly coupled to the programming languages in which these applications have been developed. This leads to problems in application integration if the applications have been developed using disparate technologies.
Developers who have developed applications using Microsoft technologies have extensively used Component Object Model (COM) technology to develop components. These components were used mainly to encapsulate the business logic of the application. COM technology suffered from the following limitations:
- Registration of COM components.
- Unloading COM components.
- Data link library (DLL) hell.
Microsoft .NET has been developed keeping the above limitations in mind and making Web services development one of its major goals.
Automatic Memory Management.
- To provide a very high degree of language interoperability
- To provide a runtime environment that completely manages code execution
- To provide a very simple software deployment and versioning model
- To provide high-level code security through code access security and strong type checking
- To provide a consistent object-oriented programming model
To facilitate application communication by using industry standards such as SOAP and XML.
- To simplify Web application development
The interoperability features of .NET allow you to work with existing unmanaged code (that is, code running outside the CLR) in COM components as well as Microsoft Win32 DLLs. It also allows you to use managed components from your unmanaged, COM-based code. These features allow you to choose if and when to migrate existing unmanaged code to .NET.
The various types of interoperability supported by .NET
Calling a COM component from .NET - When a COM object is called from .NET, the runtime generates a runtime callable wrapper (RCW). The RCW acts as a proxy for the unmanaged object.
The RCW is responsible for handling all interaction between the .NET client code and the COM component, including (but not limited to):
- Creating and binding to the underlying COM object.
- Consuming COM interfaces and factoring the interfaces into a managed form.
- Translating and marshaling data between environments.
- Managing the lifetime of the wrapped COM object.
- Translating COM HRESULT values into .NET exceptions
Calling a .NET component from COM.
When a .NET component is called from COM, the runtime again generates a wrapper object to bridge the gap between the environments. In this case, the runtime generates a COM callable wrapper (CCW). The runtime reads the type information for the component from its assembly metadata and generates a compatible CCW. Similar to the RCW, the CCW acts as a proxy between the unmanaged COM code and the managed .NET code.
Calling unmanaged application program interface (API) functions from .NET.
This interoperability, called Platform Invocation (commonly abbreviated as P/Invoke), allows managed code to call into C-language-style API functions, handles the marshaling of data types between managed and unmanaged types, finds and invokes the correct function in the DLL, and facilitates the transition from managed to unmanaged code.
A good example of P/Invoke functionality is calling one of the many Win32 API functions exposed by the Windows operating system. Through P/Invoke functionality, the runtime also supports callbacks from API functions. The current release of .NET, however, does not support calling from a Win32 DLL into .NET managed code. To call directly from unmanaged code to managed code, you must use COM interoperability.
Once you decide to migrate part or all of an existing application to .NET, you will need to decide how best to approach the migration. There are two major approaches to migration i.e. horizontal and vertical. Horizontal migration involves replacing a whole tier of your application. For example, you may choose to replace the ASP code within your Web-based presentation tier, or you may replace the COM code within your middle tier as the initial migration step. Vertical migration involves isolating and replacing a piece of your application through all n tiers.
- Choose a migration strategy that minimizes the risk of migration.
- Choose migration activities that allow you to continue to use your existing COM code base as you move to .NET.
- Quickly take advantage of the new features provided by the .NET environment.
Horizontal Migration - In a horizontal migration, you migrate an entire tier of your Windows DNA-based application to .NET without immediately migrating the other tiers. By migrating a single tier at a time, you can take advantage of the features of the .NET Framework specific to a particular tier (for example, ASP .NET on the presentation tier), in many cases without modifying application code or affecting operations on another application tier.
Choosing a horizontal migration strategy
The first step in a horizontal migration is to decide which tier to migrate first.
To replace the Web tier, you replace ASP code with code developed using ASP .NET. You may also externally expose much of your middle-tier functionality with .NET Web services. Ideally, the Web tier can be replaced with few or no changes to the middle tier. If you migrate your Web tier to ASP .NET you can make use of the following features:
- Advanced data binding functionality
- Easier configuration management
- Improved session state management
- Advanced caching capabilities
- Easy development of Web services
- Compiled code, which results in better performance
- The Web Forms programming model with server-side event handling
- Server-side controls, which make it easier to develop solutions targeting multiple browsers
To replace the middle tier, you migrate your middle-tier COM components to .NET with few or no changes to the Web tier.
In deciding whether a horizontal migration strategy is appropriate, and if so, which tier is the most appropriate for initial migration, consider whether your existing Windows DNA-based solution has the following characteristics:
- Large number of Web servers
- Shared code migration
- Heavy use of ASP Application or Session state
- Complex middle tier
Vertical Migration - Another migration approach is to migrate a portion of your application vertically through all application tiers. This essentially involves carving out a piece of your application that has minimal interaction with other pieces and migrating it. This includes both ASP code and COM components. An example might be converting the search functionality of your Web site to .NET, including the presentation tier, business tier, and data tier. The remaining functionality of the site is left in traditional COM and ASP until the time is right for migration to .NET, based on your project schedules, resources, and current system architecture. Any remaining interfaces between the new managed code and the unmanaged code function through COM interoperability.
Choosing a vertical migration strategy
You might choose to adopt a vertical migration strategy for a number of reasons:
- Good application isolation - If parts of your application are well isolated from other parts of your application, you have an excellent candidate for vertical migration. Parts of an application that are well isolated share very little state information with the rest of the application and can easily be migrated with little impact on the rest of the system.
- Adding new functionality to an existing application - when adding new functionality to an existing application, you should strongly consider using the .NET Framework to develop the new functionality.
- Heavy use of ADO recordsets between tiers - many applications pass disconnected ADO record sets from the data and business tiers to the presentation tier. They then iterate through the record sets and generate HTML tables. This type of application is well suited to a vertical migration.
- Planning to re-architect - If you plan to re-architect your application, vertically migrating part of your application to the new architecture provides a good test bed for the new design. The .NET Framework also makes it easier to provide the functionality that newer architectures are built on.
Vertical migration considerations
Before undertaking a vertical migration, you must consider the following issues:
- Application-slicing for a vertical migration
- Migration of shared code
- Session and application state management in a mixed ASP/ASP .NET environment
- Interaction between ASP and ASP .NET code in a mixed ASP/ASP .NET environment
- Interoperability and translation of managed and unmanaged data types
- Application deployment
- Configuration of COM+ based applications and .NET Enterprise Serviced Components
- Optionally using Application Center 2000 to ease deployment
Interoperability vs. Migration
The first thing to consider in terms of a migration is whether to migrate the code at all. The COM interoperability features of the .NET Framework are very powerful and, in nearly all cases, allow you to continue to use your existing code without migrating it to managed code. As you develop new parts of your application or reuse components of your application from newer managed code applications, in most cases you can simply call your existing components through the COM interoperability functionality provided by .NET. Interoperability allows you to preserve the investment that you have already made in developing and stabilizing the code, familiarizing developers with it
Overall, the overhead of calling from managed code to unmanaged code through COM interoperability is minimal. If your method performs any substantial tasks, it is likely that the overhead from the interoperability layer will be a negligible percentage of the overall method call time. However, if your method does nothing more than set a value for a property or perform some other small task, the overhead of the interoperability layer may be a significant portion of the method call. If your interface is made up of a number of these property sets and gets, known as a chatty interface, the interoperability cost may be unacceptably high.
Enhancing Development Productivity
The .NET development environment provides significant improvements to the COM-based development model for distributed applications and can significantly enhance developer productivity. If your application is expected to undergo a number of changes and development cycles in the future, you should consider migrating the application to take advantage of the higher developer productivity inherent in the .NET development platform.
Using a Managed Object Model
If most clients of your existing components will be written in managed code, you should consider either migrating your component to managed code. Your managed code clients will expect your component to look and act like a managed object. Although the RCW makes the component look somewhat like a managed component, it does not change the underlying interfaces to the component. When developing against your unmanaged component through COM interoperability, managed code developers will not be able to use parameterized constructors, static methods, inheritance, and other features they are accustomed to working with in managed code. Migrating your component or writing a managed wrapper will make your component easier to use for managed code developers.
Taking Advantage of .NET Features
In some cases, you will want to migrate parts of your application to .NET so that you can take advantage of the new features that the .NET Framework offers. For example, ASP .NET provides advanced data binding, browser-dependent user interface generation, and improved configuration and deployment. You should evaluate when the value of bringing these new features to your application outweigh the cost of code migration.
As an application developer you can face some issues as you develop your migration and interoperability plan.
- Choosing which pieces of your application to migrate
- Migration to and interoperating with ASP .NET
Choosing Pieces of Your Application To Migrate
Choosing the right pieces of your existing application to migrate is an essential task in ensuring a successful vertical migration. It is recommended that you perform a code path analysis on your current application.
Code path analysis
A typical Windows DNA-based application consists of one or more ASP pages with which a user interacts. Those ASP pages call one or more COM components, which in turn may call additional COM components. The COM components eventually access a database and either store data or retrieve data on behalf of the user. The ASP pages and components that are used during the user's single interaction would be considered a code path.
In many cases, the objects used in a code path neither depend on nor access other components in the application. Distinct code paths are a natural place to consider isolating a piece of your application for migration to .NET. Code path analysis of the application typically results in discovering pieces of your application with minimal interaction with other parts of the application, thereby minimizing interoperability needs. You can use code paths to help identify which pieces of an application are suited to vertical migration.
Interoperability for shared components
An analysis of your Web site in terms of the code paths is likely to identify components that are shared among multiple code paths. In a vertical migration, these components can be accessed through the COM interoperability functionality until all the code paths that interact with the component have been migrated. Code paths that share components between them are good candidates for migrating concurrently, minimizing the COM interoperability required.
ASP .NET Migration Guidelines
Migration guidelines specific to migration from ASP to ASP .NET and interoperating between the two environments.
Avoid or replace the ASP session object
You cannot share session state across a mixed ASP/ASP .NET environment using the intrinsic Session object. In a vertical migration, the best way to avoid this problem is to not use the intrinsic Session object in your ASP application. Numerous methods exist for working around server-based session storage and allowing information to be passed from page to page. All these methods work with both ASP and ASP .NET:
- Using cookies
- Using hidden form fields
- Encoding session information in URL strings (URL munging)
- Manually storing and retrieving session information from the database through direct ADO (from ASP) and ADO .NET (from ASP .NET) calls
- Using a custom session object that stores state in a database (This method is discussed in the following section.)
If your application does not already make heavy use of the Session object, you should generally use one of the first three methods in the previous list, all of which avoid sharing session state on the server.
Sharing state using a database
The ASP .NET Session object has the ability to store session data in a Microsoft SQL Server database automatically. However, you cannot access this data from ASP (it is stored in a binary format, which is not easily read) without considerable work and custom code on the ASP side. You also cannot directly instantiate the ASP .NET Session object through COM interoperability and use it to retrieve the session state. So, abstracting the storage and retrieval of session information away from the ASP/ASP .NET layer involves replacing the use of the built-in session object with a custom implementation for storing session state.
Any replacement used for the Session object should follow the dictionary pattern adopted by the intrinsic session objects, and should be capable of storing and retrieving named value pairs, for example:
mysessionobject("somekey") = "somevalue"
By adopting this pattern, you can replace the intrinsic session object in your existing ASP code quickly and easily. When the remaining parts of your application are converted to .NET, you can easily replace the custom implementation with the native ASP .NET session object.
Remember that if you use a custom session object (written as a COM object), each call to the object from ASP .NET will go through the COM interoperability layer, so you should try to minimize the amount of interaction you have with the session state object. Another option is to simply have separate code in each environment that reads and writes session information to the same external database.
Avoid or replace the application object
In a vertical migration, application state (in addition to session state) cannot be directly shared between the two environments using the intrinsic Application objects. Typically, the majority of information stored in application state is either data or objects that are expensive to create for each page, and is created and initialized in the Application_OnStart event in the application's global.asa file.
The simplest method for dealing with this issue is to recreate the data and objects in both environments. This allows you to maintain your existing ASP application environment and also take advantage of the equivalent and enhanced ASP .NET features such as improved caching, tracing, and deployment. This approach works well if the data is fairly static; however, if you change the data frequently, you will need to do additional work to keep the data synchronized between the environments. If you do not want to store the data in both ASP and ASP .NET, or if you change the data frequently, you will need to find an external place to store it that is accessible from both environments such as a SQL Server database.
You cannot use Server.Transfer and Server.Execute between ASP and ASP .NET pages. For interactions between the two environments, use Response.Redirect instead.
ASP .NET does not enable impersonation by default. If you use impersonation within the presentation tier to enable role-based security in the middle tier, you must explicitly enable impersonation in ASP .NET. The impersonate attribute of the identity tag in your web.config file should be set to true. For example: