find a location for property in a new city

Friday, 6 May 2011

How to convert an ASP.NET Web Forms web application into ASP.NET MVC 3

So, you have a traditional web forms web application and you are inspired by the new ASP.NET MVC 3 are you? Well this is definitely doable. In this how to guide I will tell you step by step exactly how you can add your new ASP.NET MVC 3 work into your existing ASP.NET web forms project.

1. Add references

Right click on your web root project in Visual Studio (2010 in my case) and add the following references:
  • System.Web.Routing
  • System.Web.Abstractions
  • System.Web.Mvc
  • System.WebPages
  • System.Web.Helpers

2. Configuration

Make your web.config look like this. Obviously not exactly like this, don't just paste this over the top of your glorious web.config. I'm just highlighting the necessary points that need to be fitted into your existing web.config:
<appSettings>
  <add key="webpages:Version" value="1.0.0.0"/>
  <add key="ClientValidationEnabled" value="true"/>
  <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>

<system.web>
  <compilation debug="true" targetFramework="4.0">
    <assemblies>
      <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
      <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    </assemblies>
  </compilation>
  <pages>
    <namespaces>
      <add namespace="System.Web.Helpers" />
      <add namespace="System.Web.Mvc" />
      <add namespace="System.Web.Mvc.Ajax" />
      <add namespace="System.Web.Mvc.Html" />
      <add namespace="System.Web.Routing" />
      <add namespace="System.Web.WebPages"/>
    </namespaces>
  </pages>
</system.web>
<system.webServer>
  <modules>
    <remove name="UrlRoutingModule-4.0" />
    <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
  </modules>
</system.webServer>
<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
      <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

Update: I have changed my recommendation against using <modules runAllManagedModulesForAllRequests="true"> in favour of adding the UrlRoutingModule-4.0 module with a blank precondition as I explain in my article Don't use runAllManagedModulesForAllRequests="true" for MVC routing.

However, if you disagree with me then you can make the modules section simply look like this:
<system.webServer>
  <modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>

But be warned with that setting (or at least read the above blog post link to understand what you are doing)!

3. Routing

You will need to add a global.asax file to your web application if you haven't already got one. Right click > Add > Add New Item > Global Application Class:


Now in your global.asax add these usings:
using System.Web.Mvc;
using System.Web.Routing;

Now add these lines:
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    //ignore aspx pages (web forms take care of these)
    routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");

    routes.MapRoute(
        // Route name
        "Default",
        // URL with parameters
        "{controller}/{action}/{id}",
        // Parameter defaults
        new { controller = "home", action = "index", id = "" }
        );
}

protected void Application_Start(object sender, EventArgs e)
{
    RegisterRoutes(RouteTable.Routes);
}

4. Add some standard folders to the solution

Add a folder named 'Controllers' to your web project.
Add a folder named 'Views' to your web project.
Add a folder named 'Shared' to that Views folder.
Add a web configuration file to the Views folder (web.config).
Open this web.config in the Views folder and ensure make its contents as follows:
<?xml version="1.0"?>

<configuration>
  <configSections>
    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
      <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
    </sectionGroup>
  </configSections>

  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>

  <appSettings>
    <add key="webpages:Enabled" value="false" />
  </appSettings>

  <system.web>
    <httpHandlers>
      <add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
    </httpHandlers>

    <!--
        Enabling request validation in view pages would cause validation to occur
        after the input has already been processed by the controller. By default
        MVC performs request validation before a controller processes the input.
        To change this behavior apply the ValidateInputAttribute to a
        controller or action.
    -->
    <pages
        validateRequest="false"
        pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <controls>
        <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
      </controls>
    </pages>
  </system.web>

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />

    <handlers>
      <remove name="BlockViewHandler"/>
      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
    </handlers>
  </system.webServer>
</configuration>


5. Get Visual Studio 2010 to recognise your MVC skills

If you right click the Controllers folder and select Add, you'll notice there is no Controller class to add. You need to make a change to your web project file.

Using Windows Explorer find the web project file (Web.csproj in my case) and open it in a text editor. You will need to add "{E53F8FEA-EAE0-44A6-8774-FFD645390401};" to the ProjectTypeGuids element.

E.g. mine now looks like this:
<ProjectTypeGuids>{E53F8FEA-EAE0-44A6-8774-FFD645390401};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>

6. Optional: Add a Controller (for a laugh)

Back to Visual Studio 2010 and right click the Controllers folder > Add > Controller... call it HomeController.

using System.Web.Mvc;

namespace Web.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Message = "This is MVC";
            return View();
        }
    }
}

7. Optional: Add a View (just to show off)

Right click where it says return View(); and select Add View... then click Add.

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Index</title>
</head>
<body>
    <div>
        <%: ViewBag.Message %>
    </div>
</body>
</html>

8. Optional: Try it (just to self-indulge your skills)

Now run you site and go to http://{localhost}/home

I hope this saved you the hours it took me! Please comment if you have any feedback. It would be much appreciated

More reading here if you would like to use an existing WebForms MasterPage in your new MVC project.

Follow britishdev on Twitter

43 comments:

  1. hi...I have followed all the step but it does not work!!! if u please clear the step5 more details or do u have a video clips which show the full steps?? if it, please share the link...Its urgent for me:((

    ReplyDelete
    Replies
    1. What doesn't work? what errors are u getting?

      Delete
  2. My email Id is aashik_azim@yahoo.com . Please tell me details:((

    ReplyDelete
  3. Can you elaborate on "it does not work." These were my exact steps that worked for me.

    Step 5 isn't essential, just very useful. Following it will make Visual Studio recognise your web application as an asp.net mvc application. It will optimise your IDE support for doing standard MVC things like creating new Controllers, navigating to Views.

    I'd highly recommend it but your app will still work without it.

    ReplyDelete
  4. Hi,
    i tried your solution its great, but i got stuck in one place when i type http://{localhost}/home
    it works it calls the home controller but if i do like http://{localhost} it wont call the home controller. why it wont call the home controller can u please help

    Thanks

    ReplyDelete
  5. Routing only comes into play when it cannot find an appropriate file in the file system. So I'm guessing you have a Default.aspx in your route folder (which is fairly likely if you are adding an MVC app to an existing web forms app). That will stop routing.

    Rename it temporarily to Default2.aspx just to test the theory.

    ReplyDelete
  6. Thanks, you are right

    ReplyDelete
  7. These instructions worked beautifully.

    ReplyDelete
  8. I feel like you just saved me a day. Thanks a million

    ReplyDelete
  9. Thank you, this was very helpful and indeed saved me a lot of time!

    ReplyDelete
  10. spot on thank you! My week just freed up a little! :D

    ReplyDelete
  11. Thank you, I would like to say to it`s nice post for blog.

    ReplyDelete
  12. This was very helpful. Thanks for your effort ... The point about getting VS2010 to recognize that this is now an MVC project was excellent!

    ReplyDelete
  13. Thank you for your code, but i face the problem to run it and it show the error say"Server error in"/" Application. resource cannot be found."

    can u teach me how to solve it?

    ReplyDelete
  14. The resource cannot be found.
    Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.

    Requested URL: /Views/Staff/Index.aspx

    ReplyDelete
  15. Does that view exist then? It sounds like it's missing

    ReplyDelete
  16. Hey, after following these steps the code I had in App_Code stopped working. Any idea how to workaround this?

    ReplyDelete
  17. @Saulo probably give your code a namespace and add that namespace to the list of them in step 2's config lines 19-24

    ReplyDelete
  18. Hi,
    After doing all the above steps, when i press f5
    it give me the error "A project with output type of class library cannot start be directly.
    Nausher Sayeed

    ReplyDelete
  19. @Nausher, sounds unrelated but to change that you will need to right click on your web project and select Set as StartUp project. After doing this the web project you intend to run should be highlighted in bold and clicking F5 will run that rather than whichever class library is currently set as the StartUp project.

    ReplyDelete
  20. Hi there.

    Great article. I think I am also stuck with the following issue:
    "i tried your solution its great, but i got stuck in one place when i type http://{localhost}/home
    it works it calls the home controller but if i do like http://{localhost} it wont call the home controller. why it wont call"

    How do I enable the default.aspx file to be called if someone types in domain.com? If I type in domain.com/default.aspx its working fine. Something needs to be changed in IIS (what?) or routing please?

    Thanks.

    ReplyDelete
  21. If you want your route URL to show default.aspx you will need to use ignore route like this:

    routes.IgnoreRoute("");

    ReplyDelete
  22. Great post!
    Just wanted to add that installing MVC3 first eliminated all the issues. Like Step 5 GUID wasn't working for me as well as ViewBag wasn't being seen.

    Thanks again and good job!! :D

    ReplyDelete
  23. Nice one...thanks.......

    ReplyDelete
  24. Hi everyone and thanks for this, I cant find in my .csproj I even created new MVC application to look in that .csproj and doesn't have element, anyone know why? please help

    ReplyDelete
    Replies
    1. I mean ProjectTypeGuids element

      Delete
  25. It seems this article applies to "Web Site Project" and not to "Web Application". When you create a "web site project", you get a .csproj and global.asax plus global.asax.cs. Furthermore, you can have Web Forms and MVC running in the same project as described by this article. However, if you create a "web application" you don't get a .csproj file and the Global.asax file does not have a .cs file.

    I am not very clear what the purpose of these two types of applicaions is. It seems that the purpose of "Web Applicatino" is keep compatability with VS 2003 while "Web Site Project" is the more modern project model.

    I think the author should make it clear which type of project we should use. I spent many hours until I realized that you must have a "Web Site Project" for this article.

    ReplyDelete
    Replies
    1. You got it back to front. Web Site project is the old VS2003 one and Web Application is the newer (and better) one http://msdn.microsoft.com/en-us/library/dd547590.aspx

      But you are right this is written for a Web Application not a Web Site. I didn't try converting a web site project to MVC so you may well need to convert your web site to a web application which is fairly trivial http://msdn.microsoft.com/en-us/library/aa983476.aspx

      Ps, I did mention it was a web application.. I mentioned it in the title of all places ;)

      Delete
  26. Your guide here is very useful and made this conversion a breeze for me!

    Thanks so much!
    T

    ReplyDelete
    Replies
    1. Hi Jason we did a project in 2 tire arch.......Can we convert that into MVC3 arch. If possible can u send me the detail file with screen shots what to do .
      Looking forward for your help, please do the needful asap.

      With Regards
      Suneel.P

      Delete
    2. Hi Jason we did a project in 2 tire arch.......Can we convert that into MVC3 arch. If possible can u send me the detail file with screen shots what to do .
      Looking forward for your help, please do the needful asap.

      With Regards
      Suneel.P

      Delete
  27. yep used this a couple of times worked brilliantly - thanks

    ReplyDelete
    Replies
    1. Hi Jason we did a project in 2 tire arch.......Can we convert that into MVC3 arch. If possible can u send me the detail file with screen shots what to do .
      Looking forward for your help, please do the needful asap.

      With Regards
      Suneel.P

      Delete
  28. after following the steps, when i try to add a controller i get an error, could not load file or assembly 'Microsoft.VisualStudio.QualutyTools.UnitTestFramework, Version=9.0.0.0...even after adding the 10.0.0.0 version of this dll and updating the web.config to use 10.0.0.0 instead of 9.0.0.0 i still get this error....any thoughts???

    ReplyDelete
  29. Excelent .. works! and simple. Thx!

    ReplyDelete
  30. Nice job men!!!

    ReplyDelete
  31. I am unable to add the controller. It still shows add an item. Please reply

    ReplyDelete
  32. I struggled in editing web project file. Because web site doesn't have that file. So what to do for websites?

    ReplyDelete
  33. Do you suppose this will work if the web app is in vb?

    ReplyDelete
  34. This comment has been removed by the author.

    ReplyDelete
  35. hi...I have followed all the step but it does not work!!! if u please clear the step 5,6,7 more details or do u have a video clips which show the full steps?? if it, please share the link...Its urgent for me:(( please send me my mail id:sandeep23456@yahoo.com

    ReplyDelete
  36. Hi mine is web application... however i couldn't find ProjectTypeGuids tag plz help

    ReplyDelete