How to migrate existing asp.net application to asp.net MVC pattern format

These is my step-by-step guide, based on steps we have taken at my company during our move from a classic ASP.Net Webforms to ASP.Net MVC. It’s not perfect, and still ongoing since we have to do this in stages because of the size of the site, but perhaps someone else will find and file an improved answer based on our results.

Stages:
1. Planning – moving to MVC from Web Forms in ASP.Net requires some careful planning. The mistake we made in our move is not realising that there are are really two aspects to this stage of planning, route planning and model/controller/action planning.
Not doing this will cause serious issues later on as you try to extend functionality of your site or hit more complex migrations.

Tips:
– Look at your current sitemap, and design the improved sitemap/directory structure to be used in the ASP.Net MVC application. Figure out a ‘language’ for your website, e.g. the default behaviour of ASP.Net MVC is to have a http://sitename/{controller}/{action}/{id} behavior, but you can override this as you gain more experience hacking routing rules.

  • Remember by default each Controller will be routed to via a virtual subdirectory of your application, e.g. http://sitename/X would route to XController (and by default its Index method), http://sitename/Y/Get would route to YController’s Get() method. You can change this as you please (routing’s really powerful), but that’s beyond the scope of this answer.

  • Using the existing sitemap, specify what folder in the MVC structure each current .aspx page should fall (of course, first ask if it should exist at all).

  • If Scripts, Images etc are not stored together, or in some ‘reserved name’ folders within each subdirectory, consider doing so now as you’re redesigning.
    This is as it would greatly simplify your design by allowing you to use a Map.IgnoreRoute() routing rule command in the Global.aspx.cs file to bypass processing these folders as routes.

In our case we mirrored the real subdirectory layout of the current site, where each subdirectory became a controller, e.g. /Account would have an AccountController, /X would have XController. All pages that fell inside there were replaced by actions within each Controller. e.g. http://sitename/profile/about.aspx now became http://sitename/profile/about and mapped to the “about” ActionResult method inside the profileController.
This is allowing us to stay agile by doing a partial migration of one or two directories (or several files inside one directory) over a series of sprints, rather than having to migrate the entire site in one go over a much longer duration.

  1. Create a new ASP.Net MVC application in Visual Studio and immediately create the rules in the Global.asax file that ignore routing rules for the folders that exist in the current site.

  2. Copy the folders from the ASP.Net Web Application to the ASP.Net MVC Application folders. Run the website and ensure it works properly (it should as no routing rules are being used yet).

  3. Pick a subdirectory or subset of files within a subdirectory to migrate.

  4. For each .aspx page inside this subdirectory:

    a. Create its View first. I tend to use the web-browser rendered version of the page as my base HTML, and then put placeholders in the locations that I know are filled with dynamic data.

    b. Using the placeholders for the dynamic data, create a first-draft of the Model using simple data types. This model will start off simple, but be constantly refactored as you migrate more pages from the original site, so don’t worry if it starts looking a little heavy. If you find yourself with too many Properties in one Model for your taste, or see a logical grouping beyond just the Model of certain subset of items, perhaps this is a sign the Model needs to be refactored to have an object instead with these simple data types as properties but is composed in the business logic layer.

    c. Create the controller if it hasnt been created yet, and put the appropriate ActionResult method for the Action your planning has determined should route to this view.
    If you realise something that there is a new action that doesn’t map to a page from the old site, then create the View for the controller, and include appropriate //TODO: tags so you can keep track of this to implement after you have migrated the existing pages.

    d. Consider putting in some handling code for unknown actions as well, if you don’t have a {*catchall} Routing rule for this already in your global.asax.cs file.

    e. Create the constructor classes for the Model so that given certain parameters that the Controller will have (passed in as your {id} or possibly a Request.QueryString parameter from the URL, or an HTTP header or cookie), the Model will know how to reach out to your existing business logic classes and build up itself for rendering by the View.

    f. Go to next page in the list and start again from step a.

  5. Finally create the routing rule that will call your new Controller and allow the Actions you have written to be implemented. Debug, debug, debug…Once you’re happy all is well, remove the existing folder and files you’ve migrated from your main site, as well as the IgnoreRoute rule in the global.asax.cs.

  6. Create a redirect in whatever manner you prefer if you wish to preserve old directory and file names for continuity (e.g. users may have bookmarked certain pages in the old site already).

Note: If you are keeping the exact names of the old subdirectories in your MVC site during the porting phase, it’s preferable to migrate a whole subdirectory at a time I’ve realised, because by only doing a few files the routing rules you need to write become more complex since if an existing folder exists with the same name as a routing rule’s path and that folder has a Default.aspx file then (/foldername/) will default to the Default.aspx page, as it takes precidence over the routing rules.

Tip: Seriously consider using a tool like RouteDebug for route debugging so you can figure out strange things like above, or when you have multiple routing rules firing and causing unexpected behaviors.

This is my first draft, please give me feedback if I’ve missed any steps or if you see any holes in the guide, and I’ll modify the answer appropriately.

Leave a Comment