Dependency Injection With ASP.NET HttpModules

asp.net, asp.net mvc, nuget, code 0 comments suggest edit

At the risk of getting punched in the face by my friend Miguel, I’m not afraid to admit I’m a fan of responsible use of dependency injection. However, for many folks, attempting to use DI runs into a roadblock when it comes to ASP.NET HttpModule.

In the past, I typically used “Poor man’s DI” for this. I wasn’t raised in an affluent family, so I guess I don’t have as much of a problem with this approach that others do.

However, when the opportunity for something better comes along, I’ll take it Daddy Warbucks. I was refactoring some code in Subtext when it occurred to me that the new ability to register HttpModules dynamically using the PreApplicationStartMethodAttribute could come in very handy.

Unfortunately, the API only allows for registering a module by type, which means the module requires a default constructor. However, as with many problems in computer science, the solution is another layer of redirection.

In this case, I wrote a container HttpModule that itself calls into the  the DependencyResolver feature of ASP.NET MVC 3 in order to find and initialize the http modules registered via your IoC/DI container. The approach I took happens to be very much similar to one that Mauricio Scheffer blogged about a while ago.

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using HttpModuleMagic;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;

[assembly: PreApplicationStartMethod(typeof(ContainerHttpModule), "Start")]
namespace HttpModuleMagic
{
  public class ContainerHttpModule : IHttpModule
  {
    public static void Start()
    {
      DynamicModuleUtility.RegisterModule(typeof(ContainerHttpModule));
    }

    Lazy<IEnumerable<IHttpModule>> _modules 
      = new Lazy<IEnumerable<IHttpModule>>(RetrieveModules);

    private static IEnumerable<IHttpModule> RetrieveModules()
    {
      return DependencyResolver.Current.GetServices<IHttpModule>();
    }

    public void Dispose()
    {
      var modules = _modules.Value;
      foreach (var module in modules)
      {
        var disposableModule = module as IDisposable;
        if (disposableModule != null)
        {
          disposableModule.Dispose();
        }
      }
    }

    public void Init(HttpApplication context)
    {
      var modules = _modules.Value;
      foreach (var module in modules)
      {
        module.Init(context);
      }
    }
  }
}

The code is pretty straightforward, though there’s a lot going on here. At the top of the class we use the PreApplicationStartMethodAttribute which allows the http module to register itself! Just reference the assembly containing this code and you’re all set to go. No mucking around with web.config!

Note that this code does require that you’re application has the following two assemblies in bin:

  1. System.Web.Mvc.dll 3.0
  2. Microsoft.Web.Infrastructure.dll 1.0

The nice part about this is after referencing this assembly, I can simply register the Http Modules using my favorite DI container and I’m good to go. For example, I installed the Ninject.Mvc3 package and added the following Subtext http module bindings:

kernel.Bind<IHttpModule>().To<BlogRequestModule>();
kernel.Bind<IHttpModule>().To<FormToBasicAuthenticationModule>();
kernel.Bind<IHttpModule>().To<AuthenticationModule>();
kernel.Bind<IHttpModule>().To<InstallationCheckModule>();
kernel.Bind<IHttpModule>().To<CompressionModule>();

There is one caveat I should point out. You’ll notice that when the container http module is disposed, Dispose is called on each of the registered http modules.

This could be problematic if you happen to register them in singleton scope. In my case, all of my modules are stateless and the Dispose method is a no-op, which in general is a good idea unless you absolutely need to hold onto state.

If your modules do hold onto state and need to be disposed of, you’ll have to be careful to scope your http modules appropriately. It’s possible for multiple instances of your http module to be created in an ASP.NET application.

DI for a Single Http Module

Just in case your DI container doesn’t support the ability to register multiple instances of a type (in other words, it doesn’t support the DependencyResolver.GetServices call), or it can’t handle the scoping properly and your http module holds onto state that needs to be disposed at the right time, I did write another class for registering an individual module, while still allowing your DI container to hook into creation of that one module.

In this case, you won’t be using DI to register the set of http modules. But you will be using it to create instances of the modules that you register.

Here’s the class.

using System;
using System.Web;
using System.Web.Mvc;

namespace HttpModuleMagic
{
  public class ContainerHttpModule<TModule> 
    : IHttpModule where TModule : IHttpModule
  {
    Lazy<IHttpModule> _module = new Lazy<IHttpModule>(RetrieveModule);

    private static IHttpModule RetrieveModule()
    {
      return DependencyResolver.Current.GetService<IHttpModule>();
    }

    public void Dispose()
    {
      _module.Value.Dispose();
    }

    public void Init(HttpApplication context)
    {
      _module.Value.Init(context);
    }
  }
}

This module is much like the other container one, but it only wraps a single http module. You would register it like so:

DynamicModuleUtility.RegisterModule(typeof(ContainerHttpModule<MyHttpModule>));

In this case, you’d need to set up your own PreApplicationStartMethod attribute or use the WebActivator.

And of course, I created a little NuGet package for this.

Install-Package HttpModuleMagic

Note that this requires that you install it into an application with the ASP.NET MVC 3 assemblies.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

29 responses

  1. Avatar for Paul
    Paul June 2nd, 2011

    Spring.NET does it from years now

  2. Avatar for AlexIdsa
    AlexIdsa June 2nd, 2011

    What is so wrong with dependency injection? Why should you be punched into face? :)

  3. Avatar for Darren Cauthon
    Darren Cauthon June 2nd, 2011

    Have you tried MVC Turbine? It has been doing this since MVC V1, magically behind-the-scenes and for all ioc containers. If you have a HTTP module, it resolves it out of your ioc container of choice without you having to do one additional line of code.
    Cases like these are the main reason I use MVC Turbine, and why I wish its features would g we adopted by ASP.Net MVC. Many devs, if not most, need this functionality. When its not provided by the framework, it leaves EVERY dev to write or copy-paste huge chunks of code that do exactly the same thing. Aren't these the types of problems

  4. Avatar for Vishal Pawar
    Vishal Pawar June 2nd, 2011

    nice info buddy

  5. Avatar for Justin
    Justin June 2nd, 2011

    Great post Phil. I tend to use "Poor mans DI" most of the time instead of IoC containers. I appreciate you showing how to use it with HttpModules. Thanks.

  6. Avatar for Paul Knopf
    Paul Knopf June 2nd, 2011

    Why have DI for httmodules though? Testability? Who tests httpmodules?

  7. Avatar for lynn
    lynn June 2nd, 2011

    Nifty. Gotta use this?

  8. Avatar for haacked
    haacked June 2nd, 2011

    @Paul, @Darren Do both of those approaches work without requiring changes to Web.config nor Global.asax.cs? In other words, does the mechanism for dynamic registration register itself?
    I'm unaware how that could have been accomplished before ASP.NET 4 because there was no way to self register an HTTP Module from outside of the application code without changing the application's web.config or doing some trickery within an application's global.asax.

  9. Avatar for Javier Lozano
    Javier Lozano June 2nd, 2011

    @phil, @paul, @darren -
    Prior to ASP.NET 4 this was not possible since PreApplicationStartMethod hook didn't exist in the runtime. The *only* clean way to do it was to provide your hooks into the class that inherited from HttpApplication (the type that Global.asax inherits from).
    A while back, I blogged about how you could do this in ASP.NET 2 (with MVC or WebForms) - lozanotek.com/... ... this blog post outlines the same pieces that I wired into MVC Turbine.

  10. Avatar for haacked
    haacked June 3rd, 2011

    @Javier I assume than now, MVCTurbine makes use of this hook to be even more modular, right?

  11. Avatar for Seth
    Seth June 4th, 2011

    > "... the solution is another layer of redirection"
    had me rolling on the floor :)

  12. Avatar for Chris
    Chris June 4th, 2011

    so where do you register your module, i mean where is this method called? what class?
    DynamicModuleUtility.RegisterModule(typeof(ContainerHttpModule<MyHttpModule>));
    i'm a newbie by the way. in case this question sounds odd. nice post i must say. very clear and concise

  13. Avatar for Javier Lozano
    Javier Lozano June 4th, 2011

    @Phil - Sorry the delay on the response, as you know, I've been a little busy. :)
    Unfortunately it doesn't since that was one of the pieces that I left un-touched for the MVC3 migration. However, it doesn't mean it can't use it. I'm actually in the process of making this change in the v3.3 release along with adding support for removing modules from the pipeline.
    At times having things to be auto-wired can be somewhat of a pain since they're not 'developed' with IoC principles in mind.
    Once these pieces are done, they will be available through #nuget :)

  14. Avatar for Konstantin Tarkus
    Konstantin Tarkus June 5th, 2011

    Nice, nice. I love the idea when you can register HttpModule without touching web.config file.

  15. Avatar for dotnetchris
    dotnetchris June 5th, 2011

    Shouldn't we all use WebActivator and never use PreApplicationStartMethod?
    Isn't PreApplicationStartMethod limited to 1 single usage in your entire application?

  16. Avatar for haacked
    haacked June 5th, 2011

    @chris PreApplicationStartMethodAttribute is an assembly level single use attribute. It means it's single use per assembly, not application.
    In this, the assembly would be the HttpMagic assembly that's using it, which only needed it once. Your app is in the clear to reference this assembly. :)

  17. Avatar for AlexIdsa
    AlexIdsa June 6th, 2011

    Phil, why do you ignore me? :) I'm really interested in the answer to my question about DI. Is there any new trend of hating DI?

  18. Avatar for haacked
    haacked June 6th, 2011

    @Alexldsa I didn't think that question was for me. I like DI. I don't know why folks would hate it. :)

  19. Avatar for AlexIdsa
    AlexIdsa June 6th, 2011

    Phil, but what was a reason for the twit which you told about at the top of the post?

  20. Avatar for haacked
    haacked June 6th, 2011

    @Alexldsa I don't recall the tweet. It was something Miguel De Icaza tweeted or retweeted. Ask him.

  21. Avatar for Stacey
    Stacey June 8th, 2011

    That does seem like an odd tweet to make.

  22. Avatar for Marco
    Marco September 8th, 2011

    Thanks for this Phil, made my day.
    Having worked on some PHP-applications using frameworks like Symfony, I'm fairly new to ASP.NET and this is exactly what I needed (I need to investigate and learn a lot more). Thanks again!
    About that tweet you mentioned, I don't agree... DI and unit testing = great!

  23. Avatar for Ashwin
    Ashwin September 21st, 2011

    Hi Phil,
    Thanks for your article. The one thing that we would lose by dynamically registering HttpModules is the ability to set preconditions for them without tinkering with IIS. Is there a way to programmatically set the preconditions for a HttpModule?
    Thanks,
    Ashwin

  24. Avatar for T
    T October 19th, 2011

    When you register modules using code, how do you enforce the order of execution for the modules?

  25. Avatar for Kendall Bennett
    Kendall Bennett September 4th, 2013

    Won't you have scoping issues if you inject dependencies that are request scoped into an HttpModule? Because as I understand it HttpModules exist one instance per application instance, not one per web request. So you can only really inject dependencies that are singleton scoped (and hence thread safe) and not request scoped? I already fixed a nasty bug in our code which I believe was caused by this.

  26. Avatar for Kendall Bennett
    Kendall Bennett November 3rd, 2013

    Please note that this method will work but ONLY for dependencies that are globally scoped. You cannot inject anything that might be HttpRequest scoped or you will end up with some really odd problems. One of which is those items will hang around and never get disposed of, and you WILL end up with threads stomping on them eventually causing you thread issues. This is discussed in more detail here:

    http://www.sapiensworks.com...

    However that approach is really no different to using a service locator pattern either, because the injected dependencies are just injected service locator callbacks. I think the correct solution is to update HttpModuleMagic such that it creates a new instance of service module that performs JUST the services, which is DI injected, at the time when the request first starts up. And then pass the calls from the real module to the request scoped module. Still a hack, but cleaner in that you CAN use request scoped items in the module.

    I would bet most people (myself included) who want this ARE trying to inject items that need to be request scoped (like data access layers for authentication etc), and if they do it this way they will end up with really nasty, hard to track down load induced bugs. Been there, done that. I went back to a service locator pattern for now until I can come up with something better.

  27. Avatar for Anthony Johnston
    Anthony Johnston July 25th, 2014

    This is service locator, so, if you are happy to use it, why not just locate the services you need inside a concrete handler.
    This solves the per request thing too, in that you can call the service locator in the BeginRequest or, if global, in the constructor.

    Moving the logic to a service is probably the right thing to do here anyway for testing and interchangaswappableness, leaving the HttpModule as a wrapper with the single responsibility of calling those services in a "HttpModule kind of way".

  28. Avatar for justin mason
    justin mason April 29th, 2015

    return DependencyResolver.Current.GetService<ihttpmodule>();
    Should be:

    return DependencyResolver.Current.GetService<tmodule>();

    At least I needed to make that change to get mine to work.

  29. Avatar for M V
    M V May 20th, 2017

    Some questions to assure HttpModuleMagic's functioning.

    1) What is the customHttpModule lifecycle? (It would seem "transient")
    2) Can I use the InRequestScope Lifecycle dependencies customHttpModule?

    thank you