ASP.NET MVC HttpModule Registration Under IIS Integrated Mode vs. Classic Mode

Subscribe to my feed here:  http://feeds.jeffreypalermo.com/jeffreypalermo

Context

In many applications, I find the development team needs to have some bit of configuration code run at the very beginning, before any other code.  In a web site on ASP.NET, we have the Global.asax file that has an Application_Start method.  In an ASP.NET MVC app, we register routes and do other things before the first request is served by the application.  One of the common start-up tasks my teams need to do is configuration NHibernate:  setting up the configuration, creating the SessionFactory, etc.  Because NHibernate is an infrastructure concern, one of our standards is that only the Infrastructure project has a reference to NHibernate.dll.  This presents a special need on the UI project because the UI project is not allowed to reference the start-up code explicitly. 

Solution

To get around this, we use an IHttpModule implementation to do start-up configuration.  This module lives in the Infrastructure project off to the side, and we add it to the web.config file so that the ASP.NET runtime will call it.  Here is a sample start-up module for NHibernate.  Note that the only purpose is to catch a time before the first request, and you can slide in any start-up code:

public class NHibernateModule : IHttpModule
{
private static bool _startupComplete = false;
private static readonly object _locker = new object();

public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
context.EndRequest += context_EndRequest;
}

private void context_BeginRequest(object sender, EventArgs e)
{
EnsureStartup();
new DataConfig().StartSession();
}

private void context_EndRequest(object sender, EventArgs e)
{
new DataConfig().EndSession();
}

private void EnsureStartup()
{
if (!_startupComplete)
{
lock (_locker)
{
if (!_startupComplete)
{
new DataConfig().PerformStartup();
_startupComplete = true;
}
}
}
}

public void Dispose()
{
}
}

Explanation

We are using double-checked locking to ensure we only perform the start-up code once.  This module is registered in the web.config here:

<configuration>
<system.web>
<httpModules>
<add name="StartupModule" type="Infrastructure.NHibernateModule, Infrastructure, Version=1.0.0.0, Culture=neutral"/>
</httpModules>
</system.web>
</configuration

This works fine if IIS7 is set to Classic mode.  As soon we go to Integrated Mode, which is recommended on IIS7 for ASP.NET MVC, this module registration doesn’t work.  Instead, we use the system.webServer node as shown below:

<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="StartupModule" type="Infrastructure.NHibernateModule, Infrastructure, Version=1.0.0.0, Culture=neutral"/>
</modules>
</system.webServer>
</configuration

There you have it.  Works like a charm on IIS7 in Integrated Mode.


Trackbacks

Interesting Finds: 2009 06.01 ~ 06.14 Posted on 6.14.2009 at 1:25 AM

Web How to Easily Create a JavaScript Framework, Part 1 - Part 2 Asynchronous innerHTML 10 HTML Tag Crimes

ASP.NET MVC Archived Blog Posts, Page 1 Posted on 6.14.2009 at 9:50 PM

Pingback from ASP.NET MVC Archived Blog Posts, Page 1

Comments

Brian said on 6.09.2009 at 9:50 AM

it seems sloppy to lock on every request for something which should only happen once on application startup. Why not put the code in the static constructor of the NHibernateModule? You should still have access to HttpContext.Current if you need it when that first request fires up the module, and you would remove a bit of code out of the loop (loop being the request/response cycle)

Efdee said on 6.11.2009 at 10:36 AM

@Brain: The lock only goes in effect if _startupComplete is false, which it ceases to be once the startup code has been ran, so it's hardly "on every request" :-)

Brian said on 6.11.2009 at 1:06 PM

Very good point. I realized my comment was a bit overly-opinionated after posted, but there be no edit feature, so I just sat here and cried. Note to self: post more slowly.

I still think it might be better to use that static constructor, but I could be wrong. And since it's just a little if check now, it's not nearly as big a deal. *high five*

Jeffrey Palermo said on 6.11.2009 at 1:27 PM

@Brian,

As with everything, measure, then optimize. If that code ever becomes a performance problem, it will have to change. Until then, I'm still trying to speed up network access between the web server and database server.

camaros said on 7.28.2009 at 9:23 PM

Jeffrey, I am wondering how to switch between integrated and classic mode, can you do that within a web.config?