views:

238

answers:

2

I have successfully created an iHttpModule to replace my Global.asax file in many Web Forms applications. But in looking at the Global.asax file in my MVC application, the methods are totally different.

I'm wondering if it is still possible to create this same thing in an MVC app. I know it's not necessary and the Global.asax works just fine. I suppose I just want to have nothing but the web.config in the root directory of my application.

Also, I am putting all of my classes in a separate class library project instead of a folder in my MVC application. Not sure if this makes a difference or not.

Here's what I have currently, but unfortunately my routes are not registering

MVCApplication.vb (Class)

Imports System.Web.Mvc
Imports System.Web.Routing
Imports System.Web
Imports System.Text.RegularExpressions

Public Class MvcApplication : Inherits System.Web.HttpApplication : Implements IHttpModule

#Region "Global Variables/Objects"

    Private UrlRegex As New Regex("(http|https)://www\.", RegexOptions.IgnoreCase Or RegexOptions.Compiled)
    Private ApplicationContext As HttpApplication
    Private BeginRequestEventHandler As EventHandler
    Private ErrorEventHandler As EventHandler
#End Region

#Region "Init and Dispose"

    Public Overrides Sub Dispose() Implements System.Web.IHttpModule.Dispose
        RemoveHandler ApplicationContext.BeginRequest, BeginRequestEventHandler : BeginRequestEventHandler = Nothing
        RemoveHandler ApplicationContext.Error, ErrorEventHandler : ErrorEventHandler = Nothing
    End Sub

    Public Overridable Overloads Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
        ApplicationContext = context
        AddHandler ApplicationContext.BeginRequest, AddressOf OnBeginRequest
        AddHandler ApplicationContext.Error, AddressOf OnError
    End Sub
#End Region

    Protected Sub OnBeginRequest(ByVal sender As Object, ByVal e As EventArgs)
       ''# Crap in here about redirecting WWW
    End Sub

    Protected Sub OnError(ByVal sender As Object, ByVal e As EventArgs)
        ''# crap in here about logging errors
    End Sub




    Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}")

        ''# MapRoute takes the following parameters, in order:
        ''# (1) Route name
        ''# (2) URL with parameters
        ''# (3) Parameter defaults
        routes.MapRoute( _
            "Default", _
            "{controller}/{action}/{id}", _
            New With { _
                .controller = "Home", _
                .action = "Index", _
                .id = UrlParameter.Optional} _
        )

    End Sub


    Sub Application_Start()
        AreaRegistration.RegisterAllAreas()
        RegisterRoutes(RouteTable.Routes)
    End Sub
End Class

web.Config

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
      <modules runAllManagedModulesForAllRequests="true">
          <add name="_Global" type="UrbanNow.hClassLib.MvcApplication"/>
      </modules>
  </system.webServer>
+3  A: 

What aspects of MVC do you want to push into your IHttpModule? The problem with this scenario is that an IHttpModule is executed on each request, whereas the Global.asax method is used (mostly) for performing first-run application configuration. What exactly are you trying to achieve?

You can subclass the HttpApplication class instead, and inherit from that in code, so in your supporting library, do something like this:

public class MyCustomApplication : HttpApplication
{
    public void Application_Start() {

    }
}

And change your Global.asax.cs class to inherit from MyCustomApplication instead of HttpApplication.

Matthew Abbott
Well the idea is to basically move all "code" into a separate project. This includes Global.asax.vb.
rockinthesixstring
Well, you can do that, but you probably wouldn't want to do it as an IHttpModule, you can subclass System.Web.HttpApplication instead, and simply have your Global application class inherit from that instead.
Matthew Abbott
A: 

I just ran across this looking for information on the same issue. The underlying problem is that the routing model is designed to work with the HttpApplication class, which is basically an automagically registered IHttpHandler instance with some state voodoo rather than an proper IHttpModule like the ones we can create and register in web.config.

In my attempt to move the MVC plumbing out of the main web project and into an IHttpModule I ran into the problem of multiple route registration, because as far as I can see, Init() method is sometimes executed more than once within the app domain. So by the time the second (or third) call to Init() came along, the RouteTable already had everything in place and an exception was thrown during the attempt to register duplicate routes (in this case the 'Default' default). I'm not sure what causes this, as I'd never seen it in normal ASP.NET projects. Perhaps it's something specific to MVC.

The (apparent) solution is to check the number of routes already registered and stop if it's anything other than zero:

public void Init(HttpApplication context) {
    if (RouteTable.Routes.Count == 0) {

        RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        RouteTable.Routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
        );
    }
}

This is the stock code pasted from the Global.asax added to a default MVC project, in an IHttpModule implementation that lives in a separate assembly.

This works, but I'm not feeling the love. It seems like a lot of effort just to get rid of Global.asax. I still need the separation of concerns here - the route logic should live in a separate class. But I'm guessing I'm going to go with using some kind of surrogate pattern that gets created in Global.asax based on some configuration setting, and called as needed depending on the event being handled.

Hope this helps someone googling for mvc MapRoute IHttpModule :)

kprobst