A Note for ASP.NET MVC Users

I’ve been trying all week (while interspersing this work with other work, obviously) to publish an ASP.NET MVC site that I’ve developed to serve a simple purpose, to take a form application for students applying for VA benefits over the Internet. Essentially, the page worked perfectly when I published it to our test site, but bombed when I published it to production. This was really confusing, since both sites are on the same server (which is, I know, less than ideal).

For a while, I wasn’t even getting any error messages from IIS, aside from a generic 500 error. I was finally able to get something more useful out of IIS, but even then, the problem was not immediately apparent. Let’s first step into what was going on on test, which worked fine. For this particular application I had requirement to run it on Test alongside Classic ASP code, which would not be present in Production. I was glad not to have the classic ASP code in production, as setting up an MVC app to run in this environment does take a performance hit.

First, to run an ASP.NET MVC site alongside classic ASP code, you’ll need to ensure that the App Pool is configured to run in Classic mode, and add the following to your web.config file:

<system.webServer>   
    <handlers>
        <add name="MVC" path="*" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" resourceType="Unspecified" requireAccess="None" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
    </handlers>
</system.webServer>

This will cause every request to go through the ASP.NET routing system, allowing the MVC framework to work it’s magic, but not precluding the classic ASP code from running.

Now, the default web.config file for a new ASP.NET MVC project includes the following system.webServer configuration section:

<!-- 
      The system.webServer section is required for running ASP.NET AJAX under Internet
      Information Services 7.0.  It is not necessary for previous version of IIS.
-->
<system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules runAllManagedModulesForAllRequests="true">
        <remove name="ScriptModule"/>
        <remove name="UrlRoutingModule"/>
        <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    </modules>
    <handlers>
        <remove name="WebServiceHandlerFactory-Integrated"/>
        <remove name="ScriptHandlerFactory"/>
        <remove name="ScriptHandlerFactoryAppServices"/>
        <remove name="ScriptResource"/>
        <remove name="MvcHttpHandler"/>
        <remove name="UrlRoutingHandler"/>
        <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
    </handlers>
</system.webServer>

For me, the most important part was that comment at the beginning, which pretty clearly states that you should only need the following block of configuration if you’re using ASP.NET AJAX in IIS7.

This information is false.

You need this block to run ASP.NET MVC in IIS7 under an Integrated Pipeline as well. If you don’t have it, you get obscure, almost meaningless errors about your configuration file. I hope that by the time ASP.NET MVC 1.0 Final is released that comment is updated, because I certainly felt safe removing that block of configuration because I simply am not using ASP.NET AJAX. All my JavaScript is being done using YUI, which is just the way I like it.

Now, I just need to update my Build Scripts to properly work for both Testing and Production Deployments now that I’m armed with this new information.