14 Days Free Technical Video Training from WintellectNOW

  

Integrating ASP.NET Web Forms and ASP.NET MVC

Tags: ASP.NET, ASP.NET Web Forms, ASP.NET MVC

With ASP.NET MVC being a mature platform, many Web Forms developers are wondering whether or not they should move to MVC or are thinking about integrating MVC into their existing Web Forms projects. Web Forms has caught up to MVC in many respects. For example, Web Forms V4+ supports routing, and the controls render less HTML than ever before. ViewState went on a diet and is considerably smaller. In the past some have turned to MVC to address these concerns, but no longer is this the case.

If you're interested in more content about migrating or integrating Web Forms and MVC, see my WintellectNOW video, "Migrating from Web Forms to MVC". It covers the many concerns developers face when making the decision about whether or not to migrate to a new technology (and whether or not you should at all). In the meantime, below are some practical tips and techniques required when integrating the two technologies.

MVC Integration: Setup, References, and Configuration

You can install the ASP.NET MVC 4 NuGet package that includes all the resources that you need to use MVC such as references, web.config changes, etc… Once you've installed the NuGet package there is little you need to do to use MVC except create folders named "Models", "Views", and "Controllers" (assuming you are keeping all these in the same project).

image_thumb3

The NuGet Package adds in several changes to the web.config file as well as references to the project that are worth examining. The web.config sample below shows these references:

Location: <configuration><appSettings>

Configure the ASP.NET Web Pages rendering engine settings in the <appSettings> element.

<appSettings>
  <add key="webpages:Version" value="2.0.0.0" />
  <add key="webpages:Enabled" value="false" />
  <add key="PreserveLoginUrl" value="true" />
  <add key="ClientValidationEnabled" value="true" />
  <add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>

Location: <configuration><system.web>

This code adds various namespaces to the project's compilation as well as parser filter and base types, which are settings that determine how views render. The namespace references below are the automatic imports to namespaces for use in views only. You must continue use the using keyword in C# code. The general namespace inclusion is in the previous example.

<pages pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc,
       Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
       pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc,
       Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
       userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc,
       Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
  <namespaces>
    <add namespace="System.Web.Optimization" />
    <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.Optimization" />
    <add namespace="System.Web.Routing" />
    <add namespace="System.Web.WebPages" />
    <add namespace="System.Web.WebPages.Html" />
  </namespaces>
  <controls>
    <add assembly="Microsoft.AspNet.Web.Optimization.WebForms"
     namespace="Microsoft.AspNet.Web.Optimization.WebForms"
     tagPrefix="webopt" />
  </controls>
</pages>

Location: <configuration><system.webServer><handlers>

These are the ASP.NET runtime HTTP handlers. They are what determines which .dlls service which type of requests at a low level. As demonstrated, these handlers are looking to interact with HTTP via verbs.

<handlers>
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
  <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*."
       verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule"
       scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll"
       preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*."
       verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule"
       scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll"
       preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*."
       verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler"
       preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

Location: <configuration><runtime><assemblyBinding>

Of course if you're dealing with differing versions of .NET for any type project, you must change assembly bindings. Assembly bindings declare which versions of which libraries to reference in the project. VS will compile against the new redirected binding than the default when you use the settings below:

<dependentAssembly>
  <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
  <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
  <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
  <bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly>
  <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
  <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>

After configuring the project to incorporate MVC, you'll need to setup routing.

Controllers and Routing

Routing is an essential component of MVC development, and MVC cannot work without it. In Web Forms V4 and later, routing is baked right in. What you'll need to do to ensure the proper routes are set is to create a static RouteConfig class, preferably in a file (e.g., RouteConfig.cs) inside the App_Start special folder. After that, add in the code below to assign a generic route.

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

Of course, the RouteConfig class won't instantiate itself. That means you must call its RegisterRoutes function (also static) from the Global.asax.cs file like so:

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

The last thing to do is use MVC conventions to create the appropriate folders for Models, Views, and Controllers, if you haven't already. Otherwise, structure your project as you would for use with the MVC pattern, perhaps moving models to their own class library or service layer.

Considerations when integrating Web Forms and MVC

DataSets/DataReaders & Models:

A lot of data is accessed by Web Forms via declarative tags like the <asp:SqlDataSource>, as well as volumes of DataSets and DataReaders in the code behind files. You'll need to find a strategy for converting these to models, i.e., classes. Some Web Forms projects contain POCOs for models and those often port over quickly. By convention (assuming a single project), model files live in the <ProjectRoot>\Models folder and model classes in the <Project>.Models namespace.

ASPX & Views:

ASP.NET MVC ships with two view engines: Web Forms (ASPX) and Razor. The ASPX view engine continues on using the classic <%# %> syntax for code delimiters, while Razor uses only the @ symbol (or @{}) as a way to denote the start of of code. Razor uses a new parsing engine first introduced in ASP.NET Web Pages that produces clean and concise HTML output. However, if you have a team strong in Web Forms they may want to continue using Web Forms syntax. The difference worth mentioning is that the ASPX view engine uses the traditional Web Forms rendering under the hood so technically it builds a control tree and renders it. You just can't access the elements in MVC views like you can in a Web Forms page by referring to a control as an object in the code behind. This makes Razor much faster as there is no tree to render. In  views, code renders inline, or in placeholders, rather than from scripted code in a code behind. This is a drastic enough difference that you'll probably need to completely rewrite many Web Forms as MVC views, as opposed to simply reusing pages in MVC. Of course, redoing all pages as views all at once is often not an option because of time and budget, but you can move them one by one.

Any would be controls in MVC become Html helpers. Html Helpers are the cornerstone of ASP.NET MVC views. Like controls, the Html Helpers render chunks of browser friendly output, but helpers emit the least amount of code as possible and in the least obtrusive way. Helpers also accept and render data from the model. This means if you have 3rd party controls, you might want to migrate these pages last or weigh the option of leaving them as Web Forms. This, of course, depends upon the cost-benefit of the developer's time to build a control vs. buying a new version of one, if one is available. Most popular 3rd party vendors are up to date.

Code Behind Files & Controllers:

It is not uncommon to see a Web Forms code behind file with 5,000+ lines of code. That's a lot of code for one single Page object. It also makes the page object a Swiss army knife of sorts as Page objects deal with building the UI and doing all sorts of other things. Many developers add CRUD operations directly in the code behind. This page of all trades ends up doing all the chores and this means more complex code and code that is tightly coupled.

MVC leans toward a concept called Separation of Concerns in which each part of the MVC pattern maps to a concern. M for models or data and CRUD operations. V for views or UI. C for controllers or operational code. All the layers are nicely separated. If your Web Forms code is getting a bit unruly or spaghetti-like then MVC could address and fix some of your maintenance issues by breaking out components into manageable units, or concerns.

Controllers of course make the calls to Web services to retrieve JSON or XML data or directly to the database, a repository, or any number of options. Controllers also do the work of determining how HTTP requests are handled. This responsibility falls to the code behind in Web Forms.

ASP.NET Core:

Since it's all ASP.NET, you get to share core features such as sessions, caching, globalization, Forms authentication between Web Forms and MVC. 

Summary

Fortunately assets like images, CSS, and custom JavaScript are all reusable between Web Forms and MVC projects. Just keep the ID and NAME attributes the same (which you want anyway for consistency). As you can see, both technologies are ASP.NET so they can live harmoniously and even compliment each other.

As you can see, with just a few modifications to a Web Forms project and you can start adding MVC components. You can run both Web Forms and MVC or work toward doing a complete migration.

4 Comments

  • Patrick said

    Hi Rachel. So, I kind of feel like there are a few somewhat conflicting sentiments in this article.

    At first, you start out by saying that WebForms has come a long way and that there might not really be a need to migrate from WebForms to MVC.

    Then, most of the rest of the article sort of implies that you generally would want to migrate to MVC due to improvements like separation of concerns, more maintainable code, and potentially higher performing code.

    Do you feel that MVC is generally favorable over WebForms or do you think that the advantages of MVC are outweighed by other factors with WebForms?

    Given greenfield projects, when would you personally chose WebForms? When would you chose MVC? Do you have any articles discussing these options?

    Thank you for your time.

  • rachel said

    Patrick,

    I happen to like MVC a bit more so I suppose you could say that's colored some of the post that you noticed. So for me, yes, I'd go MVC for greenfield unless there is some major reason to do otherwise.

    One factor if you're on a team is where the team strengths are, so if you're a Web Forms shop already you might want to stick with it. I really wanted to make the impression that thinking Web Forms is going away is not a good reason (as it is untrue), but I hear it cited often as the reason people move.

    Check out www.asp.net they have daily links to ASPNET articles.

  • rachel said

    Suraj,

    My personal favorite is MVC, but keep in mind Web Forms can bring lots of value to the table. I do like Web Forms and as always, the correct choice always depends on the requirements of the project.

Comments have been disabled for this content.