11

I have a custom HTTP Module. I would like to inject the logger using my IoC framework, so I can log errors in the module. However, of course I don't get a constructor, so can't inject it into that. What's the best way to go about this?

If you need the specific IoC container - I'm currently using Windsor, but may soon move to AutoFac.

Thanks

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
UpTheCreek
  • 31,444
  • 34
  • 152
  • 221
  • You could use a service locator, take a look at this question: [Difference between dependency injection and service locator pattern](http://stackoverflow.com/questions/1557781/whats-the-difference-between-the-dependency-injection-and-service-locator-patter) – FinnNk Nov 01 '09 at 16:00

4 Answers4

10

First time I saw dependency injection to HttpModules in Spring.NET (not advertising this framework though). The idea is that you have special HttpModule which injects dependencies to other application-level HttpModule-s.

Unfortunatelly current version of Autofac.Integration.Web does not support this, but you can easily do that yourself:

public class MyModule : IHttpModule
{
    public void Dispose()
    {            
    }

    public void Init(HttpApplication context)
    {
        Assert.IsNotNull(MyService);
    }        

    public IMyService MyService { get; set; }
}

public class HttpModuleInjectionModule : IHttpModule
{
    public void Dispose()
    {            
    }

    public void Init(HttpApplication context)
    {
        var containerProviderAccessor = context as IContainerProviderAccessor;

        if(containerProviderAccessor == null)
            throw new InvalidOperationException("HttpApplication should implement IContainerProviderAccessor");

        var rootContainer = containerProviderAccessor.ContainerProvider.ApplicationContainer;

        foreach (string moduleName in context.Modules.AllKeys)
            rootContainer.InjectProperties(context.Modules[moduleName]);
    }
}

public class Global : HttpApplication, IContainerProviderAccessor
{
  static IContainerProvider _containerProvider;

  protected void Application_Start(object sender, EventArgs e)
  {
    var builder = new ContainerBuilder();
    builder.Register<MyService>().As<IMyService>();
    _containerProvider = new ContainerProvider(builder.Build());
  }

  public IContainerProvider ContainerProvider
  {
    get { return _containerProvider; }
  }
}

HttpModuleInjectionModule should be registered before other HttpModule-s in web.config:

  <httpModules>
   <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
   <add name="HttpModuleInjection" type="WebTest.HttpModuleInjectionModule, WebTest"/>
   <add name="ContainerDisposal" type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web"/>
   <add name="PropertyInjection" type="Autofac.Integration.Web.PropertyInjectionModule, Autofac.Integration.Web"/>
   <add name="MyModule" type="WebTest.MyModule, WebTest"/>
  </httpModules>

I'm sure you can do similar things in Windsor. The difference would be in how you access your root container from HttpModuleInjectionModule.

andrey.tsykunov
  • 2,896
  • 2
  • 32
  • 21
5

I just answered this question on my blog.

See also http://lozanotek.com/blog/archive/2009/08/19/Autowire_IHttpModules_with_IoC.aspx

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
Mauricio Scheffer
  • 98,863
  • 23
  • 192
  • 275
3

You could pass in the required dependencies via the HttpApplication context passed to you by the Init method...

public class MyHttpModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        var dependency = (IDependency)context.Context.Items["dependency"];
        // consume dependency...
    }

    public void Dispose()
    {
    }
}
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • @Mauricio Scheffer: Perhaps, but then just implement the module as a Humble Executable. I prefer that approach over using static injection. People think it helps testability, but it really hurts it. – Mark Seemann Nov 03 '09 at 16:22
  • 1
    Humble Executable certainly works well in this case, I would add that piece of information to the answer. However, you can have your cake and eat it too, see my solution. – Mauricio Scheffer Nov 03 '09 at 16:41
  • 1
    Is this solution considered an implementation of Service Location Design Pattern? – Parth Shah Sep 03 '14 at 03:15
  • @ParthShah Good observation. Yes, it's a variation of the [Service Locator anti-pattern](http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern). The only reason I suggested it is because of the constraints of implementing an `IHttpModule`. – Mark Seemann Sep 03 '14 at 07:25
1

I am curious about andrey-tsykunov's answer, but don't have the rep to comment on it.

I am trying to get comfortable with IoC and DI, so I may be missing something, but wouldn't it be simpler to use IContainerProviderAccessor from within MyModule, rather than create another module?

For example:

public class MyModule : IHttpModule
{
    public void Dispose()
    {            
    }

    public void Init(HttpApplication context)
    {
        Assert.IsNotNull(MyService);

        var containerProviderAccessor = context as IContainerProviderAccessor;

        if (accessor != null)
        {
            IContainer container = containerProviderAccessor.ContainerProvider.ApplicationContainer;
            MyService = container.Resolve<IMyService>();
        }
    }

    private IMyService MyService { get; set; }
}
Jeff Ogata
  • 56,645
  • 19
  • 114
  • 127