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
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.
I just answered this question on my blog.
See also http://lozanotek.com/blog/archive/2009/08/19/Autowire_IHttpModules_with_IoC.aspx
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()
{
}
}
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; }
}
精彩评论