Archives
-
Migrating a large web application to ASP.NET MVC
Recently I had the luck of migrating some classic ASP pages to ASP.NET MVC. I would share some of the experiences below.
ASP.NET webform and ASP.NET MVC can coexist just fine
We have a huge existing ASP.NET webform application with thousands of pages. The challenge therefore is that any addition developed using ASP.NET should not affect the operation of existing webform pages. The mixing of ASP.NET Webform and MVC has been studied previously by many people. It is fairly easy to find some articles by searching “asp.net mvc and webforms together” on your favorite search engine. Basically, we need to include 3 additional DLLs in the web application:
- System.Web.Routing
- System.Web.Abstractions
- System.Web.Mvc
The System.Web.Routing is not part of ASP.NET MVC, but is used by MVC to route a web request to a controller. The System.Web.Abstractions add a wrapper to some built-in asp.net classes such as Request, Response, Session to decouple MVC code from the ASP.NET built-in classes so that these classes can be mocked in testing projects.
The first step to enable routing is to add the URLRoutingModule to the list of HTTP Modules in web.config:
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule,System.Web.Routing, Version=3.5.0.0,Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
The next step is to configure the route. In order not to interfere with the operation of existing asp.net pages, we want to exclude all of them from routing in global.asax:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");
routes.IgnoreRoute("{resource}.asmx/{*pathInfo}");
routes.IgnoreRoute("{resource}.svc/{*pathInfo}");
routes.IgnoreRoute("{resource}.ashx/{*pathInfo}");
AreaRegistration.RegisterAllAreas();
In the last line, we used an ASP.NET feature called Areas that I will discuss later.
The third step is to add a bunch of namespaces to <Pages> in web.config so that some MVC namespaces can be used in MVC view pages. We skipped this step because we do not want to affect the existing pages with bunch of new namespaces. We will do this as part of the Area implementation.
ASP.NET MVC allows 100% of the code in the library DLLs
In order to allow developers work independently, we actually split the application into multiple web applications. By default, ASP.NET MVC project put models, views and controllers in a single project. It is in fact very easy to move models and controllers into a separate library DLL, leaving the web application project only the view pages. On deployment, we simply deploy the DLLs to the bin directory of the application root, and the view pages into directories under the Areas folder (see below).
The ASP.NET MVC Areas feature is one of the best feature in MVC 2 for large projects
There are many resources about MVC Areas on the internet. For example, one can read Phil Haack’s original article on the subject. With areas, the responsibility for registering route is delegated to a subclass of AreaRegistration which now lives in our library project. When AreaRegistration.RegisterAllAreas() is called, ASP.NET will search for all AreaRegistration subclasses in all assemblies in the bin dir so that we do not have to modify the global.asax when we add new areas.
In the AreaRegistration subclass, we would do something like:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Services",
"Sub1/Sub11/Sub111/{controller}.mvc/{action}/{id}",
new { action = "Index", id = "" },
new string[] { "My.Custom.Namespace.Controllers" }
);
}
Note that we use an optional parameter to route the request to the controllers under particular namespace so that we can retain our existing namespace structure. Also, this approach allows us to blend the new mvc URLs into the existing application URLs very well.
Our web applications are only left with views. We just need to deploy these views to the web server under appropriate area directories. This is how an Areas directory may look like:
Note that we have a web.config in the Areas directory? That is the place we add a HttpNotFoundHandler to protect all the views from getting accessed directly. We also add the appropriate attributes, and namespaces to the <Pages> element so that we apply these configurations only to the view pages.
Summary
In summary, ASP.NET MVC allows us to put 100% of code into many library dlls that can be independently developed. The areas feature allows us to delegate the responsibility of route registration to each individual dll as well as centrally apply namespaces and attributes to view pages without affecting the existing asp.net webform pages.