ASP to ASP.NET Migration Strategy

Migration from ASP to ASP.NET can be done in different ways. Understanding possible paths leads to optimal strategies.


May 01, 2005
URL:http://www.drdobbs.com/web-development/asp-to-aspnet-migration-strategy/184406077

Mark is a senior enterprise architect for a consulting company. He can be contacted at [email protected].


Making the appropriate selection of an ASP to ASP.NET migration strategy is not always clear cut. As a developer, you would probably be tempted to rewrite the entire web application in Microsoft .NET from scratch. However, your manager might not be as enthusiastic as you are to this idea. The application is already in production and satisfies the requirements. Why follow a more risky and costly path if it is possible to start extending the application in .NET and at the same time preserving an investment in the legacy ASP code? Especially if a complete migration can be achieved gradually in a number of evolutionary migration steps, with every step resolving a concrete migration-justifiable problem.

Side-By-Side Approach

Migration is not necessarily an "all or nothing" proposition. ASP and ASP.NET can run side-by-side (coexist) at the same time. A web site or web application within a site can contain both ASP and ASP.NET pages. Legacy code can be replaced later in one shot, or gradually as necessary, or never replaced at all. The side-by-side approach has its own pros and cons; see Table 1.

It is important to emphasize that even with a minimalist "do not touch legacy code" strategy, some changes to this code must be done. They are:

Legacy code can be migrated gradually, while applying migration strategies and running legacy code for a long period of time until a complete migration is achieved. In this case, all problems and benefits of the side-by-side approach continue to exist for the duration of this process.

The idea behind the side-by-side approach relies on the assumption that legacy code and .NET code implement different parts of the application with low coupling between them. There are three possible solutions:

Figure 1 illustrates legacy application functionality exposed to the .NET part of a side-by-side application. Note that this article discusses logical layers and not physical tiers of application deployment. Figure 2 illustrates .NET application functionality exposed to the legacy part of a side-by-side application.

The side-by-side approach has its own problem that does not exist for any one ASP or ASP.NET application separately: state synchronization between ASP and ASP.NET environments. ASP and ASP.NET have different state management. This means that a custom application and session state management synchronization has to be developed and minimal legacy code changes have to be made.

There are two major ways to synchronize state in the side-by-side scenario:

Client-Based Synchronization

With client-based synchronization, the application and session states ("state") can be shared by passing state data through the browser. This way, the state is passed from page to page with request/response data. The possible methods are:

If a legacy application uses one of these methods to pass state between pages already, then no adjustments in legacy code are needed. Otherwise, if intrinsic Application or Session objects are used, then the object's state can be passed back and forth between ASP and ASP.NET pages using one of the three methods just mentioned.

The first two options have more restrictions, such as the size of the state and disabled cookies, but do not differ conceptually from the last one. Figure 3 illustrates client-based state synchronization. Table 2 lists the pros and cons of client-based synchronization.

The client-based synchronization approach can be implemented by developing two intermediate pages that will sit between ASP and ASP.NET pages involved in client-based synchronization. These pages, named "ClientBasedSync.asp" and "ClientBasedSync.aspx," are in Figure 4. Here, the ASP page uses Server.Transfer to the first intermediate ASP page ClientBasedSync.asp, instead of redirecting directly to the destination ASP.NET page. The ClientBasedSync.asp generates a temporary form on the fly, placing state variable names/value pairs into its hidden fields, and redirects it to the second intermediary ASP.NET page ClientBasedSync.aspx. This page assigns state variables of the ASP.NET part of the application and uses Server.Transfer to the destination ASP.NET page.

Notice, however, that only one trip to the client's browser is needed. A similar approach works in another synchronization direction—from an ASP.NET to an ASP client-based synchronization implementation. If state contains more complex types, not simple strings or numbers, then they have to be serialized to be understandable by both environments.

Server-Based Synchronization

With server-based synchronization, the state can be shared by passing data through a common location at the server side. This location can be a:

ASP.NET supports both options, but classic ASP does not support them. ASP.NET saves the state in a proprietary binary format that can be changed in the future. The ASP.NET state cannot be directly instantiated from classic ASP. This makes it difficult to use an ASP.NET state from an ASP part of the application. The better solution will be to rely on some custom common state format, which both ASP and ASP.NET can access and understand. In this case, a custom server-side synchronization has to be developed in-house or third-party software must be acquired.

The replacement of built-in ASP and ASP.NET state management with a custom one should follow the dictionary pattern by manipulating key/value pairs:

CustomStateObject(theKey) = theValue

This lets you easily replace the native ASP and ASP.NET state implementation by preserving the nature in which both of them access state. Later, after complete migration, this custom solution is easily switched to the native ASP.NET state implementation. Figure 5 shows two possible ways of accessing a common state from legacy code: through the callable wrapper and directly. By accessing state through the CCW, the common code is not duplicated, but an interoperability overhead exists. Table 3 lists the pros and cons of server-based synchronization.

Static versus Dynamic Synchronization

There are two ways to synchronize state that can be achieved by using any one of client-based or server-based synchronization:

Static synchronization can be utilized if Application and/or Session states are updated by only a small percentage of web site pages. This presumes the static nature of the web site state. The static state nature opens a way of saving on state synchronization. Instead of synchronizing state on every new page request, the state can be synchronized while leaving only the pages that update the state.

With static synchronization, both ASP and ASP.NET states have to be constantly in sync and it is the developer's responsibility to maintain them by not forgetting to update the state. Update the ASP.NET state while leaving an ASP page that updated the ASP state and arriving at the ASP.NET page. For the opposite direction, update an ASP state, while leaving an ASP.NET page that updated the ASP.NET state and arriving at the ASP page.

State for static synchronization has to be created in Application_OnStart and Session_OnStart event handlers for both global.asa and global.asax files. This gives a synchronous start to both ASP and ASP.NET components of a side-by-side application.

Static synchronization can be achieved easily by passing state in hidden fields with client-based synchronization. State can also be passed, using server-side synchronization, through the database to all pages, called by the updating state page. Table 4 lists the pros and cons of static synchronization.

Dynamic synchronization has to be used if a significant amount of pages update the state. In this case, there are no performance gains because the state has to be synchronized constantly. Dynamic synchronization should occur automatically on loading and unloading every page, freeing you from adding synchronization code manually. By replacing ASP and ASP.NET states with custom state management, the same state storage is synchronously used by both. Table 5 lists the pros and cons of dynamic synchronization.

Migration Strategies

The side-by-side approach lets legacy code and new .NET code coexist for a period of time. Even if the existing legacy code is completely satisfactory, in many cases it is better to relocate some common functionality into a new .NET part of a web site.

Migration ranges from local to complete migration of the application as a whole. Different strategies can be applied at different stages of this migration process, ending with a complete migration or the end of application support, whichever comes first.

A partial migration interoperability plays an important role in connecting the unmanaged and managed worlds. RCW and CCW are two major ways to interoperate. The unmanaged code in native Win32 DLLs can also be called through interoperability, known as "Platform Invocation" (P/Invoke). However, the .NET Framework does not support calling from Win32 DLLs into .NET managed code. To call directly from unmanaged to managed code, COM interoperability must be used.

The main migration strategies are local migration, horizontal migration, vertical migration, and rewrite and optimization.

Local Migration

Local migration is the migration of a cohesive part of one of the legacy application layers. Underlying layers' code, tightly coupled with this part, can also be migrated. In most cases, it will be a migration of some part of a business layer, with a corresponding data layer part. Another option includes migrating part of a presentation layer, which is based on complex business logic, left in legacy code. Figure 6 illustrates these options.

Some of the reasons for local migration can be:

Local migration implies calling between legacy unmanaged code and .NET managed code through the interoperability layer (if no duplication is selected). The RCW and CCW, depending on the direction of invocation, translate data between two environments. Some blittable data types, such as integers, floats, and so on, do not require translation. Nonblittable data types, such as strings, require translation. Nonblittable data-type conversion overhead affects performance.

In many cases, this performance overhead is negligible compared to the amount of work the concrete component (COM or .NET) is doing. If, however, a lightweight component is accessed in a chatty fashion, then this overhead can be significant. Setting and getting different component properties multiple times could have a performance impact, since every call crosses an interoperability boundary.

Another problem can appear if the existing COM interface does not satisfy a .NET client for reasons other then performance; for example, when it has to be redesigned.

Both problems can be resolved by creating a Custom Managed Wrapper (CMW) in front of the RCW. The CMW allows exposure of an existing COM component to a .NET client by including the necessary additional code into this managed adapter. The CMW consumes the RCW internally and delegates most of the calls to COM through it. The legacy code can continue accessing the COM component directly without any change.

CMW enables to take advantage of:

Figure 7 illustrates this approach, while Table 6 lists the pros and cons of local migration.

Horizontal Migration

Horizontal migration involves migration of an entire layer of the application. Figure 8 illustrates horizontal migration. Horizontal migration can also be done in pairs: business and data layers, for example. Horizontal migration can imply additional cost and time for mapping data between layers. For example, migrating the data layer and keeping other layers as-is requires conversion between an ADO.NET dataset and an ADO recordset. Table 7 lists the pros and cons of presentation-layer migration.

To transparently replace business layer COM components with .NET classes, without affecting the legacy presentation layer, GUIDs and/or ProgIds of these COM components must be maintained. The interoperability assemblies have to be deployed. Table 8 lists the pros and cons of business-layer migration.

Data-layer COM component migration can be done with the same approach, and in general, repeats the pros and cons of the business-layer COM components migration. There is no need for ADO recordset and ADO.NET dataset conversion if layers were optimized to consume the ADO.NET DataSet and/or DataReader.

Vertical Migration

Vertical migration involves the migration of an application portion vertically through all application layers. This involves identifying a logical piece of a web application having minimal interaction with other pieces and migrating it. Both ASP code and COM components, implementing rather independent pieces of application functionality, are potentially good candidates for vertical migration. The remaining functionality of the site runs side-by-side with the vertically converted part and can be migrated later, based on project schedules and resources.

The vertically migrated part of the app communicates with the legacy code using .NET interoperability. This interoperability should be minimal, reflecting low coupling between the vertically migrated part and the rest of the application. Figure 9 illustrates a vertical migration, and Table 9 lists the pros and cons of vertical migration.

Rewrite and Optimization

The rewrite/optimization can be done after migration, in parallel with it or instead of it. This lets you gain such .NET benefits as: layered application architecture (in case the legacy application did not have layered architecture prior to migration), caching, separation of HTML views from code behind, server controls and data binding, server events, view state, the .NET exception handling, improved developer productivity, improved maintainability, and so on.

Migration Guidelines

Here are some common migration guidelines and suggestions:

The migration lifecycle contains four major steps that are repeated iteratively if necessary:

In horizontal migration, these steps are iterated for every layer. In vertical migration, they are iterated for every functional module. In local migration, they are iterated for local functionality. Local migration can be combined with a horizontal or vertical migration strategy. Figure 10 illustrates the dynamics of a migration process.

Conclusion

Migration from ASP to ASP.NET can be done in different ways. Understanding possible migration strategies, their drawbacks and benefits, helps software architects and developers in selecting an optimal migration strategy and its implementation.

DDJ

May, 2005: ASP to ASP.NET Migration Strategy

Figure 1: Common business functionality is encapsulated in a COM object and accessed from .NET managed code by the RCW.

May, 2005: ASP to ASP.NET Migration Strategy

Figure 10: Migration state diagram.

May, 2005: ASP to ASP.NET Migration Strategy

Figure 2: Common business functionality has been moved into managed code and exposed to unmanaged code by the CCW.

May, 2005: ASP to ASP.NET Migration Strategy

Figure 3: Client-based state synchronization.

May, 2005: ASP to ASP.NET Migration Strategy

Figure 4: ASP to ASP.NET client-based synchronization implementation.

May, 2005: ASP to ASP.NET Migration Strategy

Figure 5: Server-based state sharing.

May, 2005: ASP to ASP.NET Migration Strategy

Figure 6: Local migration main options.

May, 2005: ASP to ASP.NET Migration Strategy

Figure 7: Migration and a Custom Managed Wrapper.

May, 2005: ASP to ASP.NET Migration Strategy

Figure 8: Horizontal migration.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.