IoC如何将依赖项注入到自定义HTTP模块中?(ASP.NET)

11

我有一个自定义的HTTP模块。我想使用我的IoC框架注入记录器,以便可以记录模块中的错误。但是,由于没有构造函数,所以无法将其注入到其中。有什么最好的方法来解决这个问题?

如果您需要特定的IoC容器-我目前正在使用Windsor,但可能很快会转到AutoFac。

谢谢


你可以使用服务定位器,看一下这个问题:依赖注入和服务定位器模式的区别 - FinnNk
4个回答

10

我第一次在Spring.NET中看到了将依赖注入到HttpModules中。这个想法是有一个特殊的HttpModule,它将依赖注入到其他应用程序级别的HttpModule中。

不幸的是,当前版本的Autofac.Integration.Web不支持这一点,但你可以很容易地自己实现:

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; }
  }
}

在web.config中注册HttpModuleInjectionModule应该在其他HttpModule之前:

  <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>

我相信你可以在Windsor中做类似的事情。不同之处在于你如何从HttpModuleInjectionModule访问你的根容器。


这很有限,不能进行构造函数注入。 - Mauricio Scheffer


3
你可以通过由Init方法传递给你的HttpApplication上下文传递所需的依赖项...
public class MyHttpModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        var dependency = (IDependency)context.Context.Items["dependency"];
        // consume dependency...
    }

    public void Dispose()
    {
    }
}

@Mauricio Scheffer:也许,但那只是将模块实现为谦虚可执行文件。我更喜欢这种方法而不是使用静态注入。人们认为它有助于可测试性,但实际上会损害它。 - Mark Seemann
1
谦卑可执行文件在这种情况下确实很有效,我会将这个信息添加到答案中。然而,你可以两全其美,看看我的解决方案。 - Mauricio Scheffer
1
这个解决方案是否被认为是服务定位设计模式的实现? - Parth Shah
@ParthShah 很好的观察。是的,这是服务定位器反模式的变体。我建议它的唯一原因是实现IHttpModule的限制。 - Mark Seemann

1

我对andrey-tsykunov的回答很好奇,但是我没有足够的声望去评论它。

我试着熟悉控制反转(IoC)和依赖注入(DI),所以我可能还有什么不理解的地方,但是使用IContainerProviderAccessor在MyModule内部会比创建另一个模块更简单,不是吗?

例如:

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; }
}

5
你在这里并没有使用依赖注入,而是在使用服务定位。 - Mauricio Scheffer
6
看起来你解决了声望的问题 :P - Ruben Bartelink

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接