使用Simple Injector和IHttpControllerActivator解决ASP.NET Web API中



我目前正在使用Simple Injector将依赖项解析到我的Asp.Net Web Api项目中。

从文档中,您可以这样配置它:

protected void Application_Start() {
    // Create the container as usual.
    var container = new Container();
    container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
    // Register your types, for instance using the scoped lifestyle:
    container.Register<IUserRepository, SqlUserRepository>(Lifestyle.Scoped);
    // This is an extension method from the integration package.
    container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
    container.Verify();
    GlobalConfiguration.Configuration.DependencyResolver =
        new SimpleInjectorWebApiDependencyResolver(container);
    // Here your usual Web API configuration stuff.
}

这里的要点是注册WebApi控制器并设置自定义依赖关系解析器。

然而,我刚刚阅读了Mark Seemann关于如何在Asp.NetWebApi:中配置依赖项注入的文章

  • ASP.NET Web API的依赖注入和生存期管理
  • 带有Castle Windsor的ASP.NET Web API中的依赖项注入

从这些文章中,我了解到有一个比实现IDependencyResolver更好的选项来解决WebApi依赖关系。另一个选项是创建IHttpControllerActivator的实现,该实现充当IoC容器上的适配器。

以下是我使用SimpleInjector编码的实现:

public class SimpleInjectorControllerActivator : IHttpControllerActivator
{
    private readonly Container _container;
    public SimpleInjectorControllerActivator(Container container)
    {
        _container = container;
    }
    public IHttpController Create(HttpRequestMessage request,
        HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        request.RegisterForDispose(_container.BeginExecutionContextScope());
        return (IHttpController)_container.GetInstance(controllerType);
    }
}

Application_Start方法中,我替换了这一行:

GlobalConfiguration.Configuration.DependencyResolver =
    new SimpleInjectorWebApiDependencyResolver(container);

通过这条线路:

GlobalConfiguration.Configuration.Services.Replace(
    typeof(IHttpControllerActivator),
    new SimpleInjectorControllerActivator(container));

我想知道IHttpControllerActivator的实现是否有效,以及这种方法是否有效,是否会像正常方法一样好?

是的,您的实现是有效的。

请注意不要在同一应用程序中同时使用SimpleInjectorWebApiDependencyResolverSimpleInjectorControllerActivator。两者都启动一个ExecutionContextScope,这可能导致在同一个web请求中有两个作用域,因此它们是互斥的。

与依赖解析程序相比,使用控制器激活器的一个普遍优点是,当无法创建服务时,依赖解析程序约定会强制适配器返回null。这是开发人员遇到的一个非常常见的问题,它经常导致令人困惑的控制器没有默认的构造函数异常。使用IHttpControllerActivator时不存在此问题,因为契约强制您返回值或引发异常。

然而,Simple Injector Web API集成项目通过在请求的服务是API控制器的情况下从不返回null(而是抛出异常)(从而隐式地破坏IDependencyResolver的契约)来防止依赖解析程序出现此问题。

使用SimpleInjectorDependencyResolver的一个优点是,创建在执行上下文范围内操作的消息处理程序变得更容易,因为您可以通过调用request.GetDependencyScope()方法来触发此范围的创建。对于当前的实现,作用域只是在创建控制器时启动,也就是在运行处理程序之后。改变这一点并不难,但需要改变控制器激活器,并有一个最外层的处理程序来启动执行上下文范围(或者再次依靠管理执行上下文范围的依赖关系解析器)。

Mark Seemann的一个论点是,很难传递上下文,这是一个非常有效的观点,只要你的组件在构建过程中不需要这个上下文。但使用SimpleInjector时不会遇到这种问题,因为有一种扩展方法可以帮助您访问HttpRequestMessage。因此,尽管IDependencyResolver抽象不是为获取上下文信息而设计的,但有一些方法可以获取这些上下文信息。

过去,我们决定为IDependencyResolver使用适配器,主要是因为这是所有DI容器的常见做法。我对这个决定有些遗憾,但现在使用SimpleInjectorDependencyResolver通常是将SimpleInjector插入Web API的最简单方法。我们也考虑添加SimpleInjectorControllerActivator,但这对大多数用户没有实际好处,同时我们仍然需要记录何时使用什么。因此,我们决定坚持使用依赖解析程序适配器;正如您所看到的,激活器的适配器很容易为任何需要它的人创建。

然而,对于ASP.NET Core,我们转向了另一个方向,正如您在文档中看到的,集成包实际上包含了一个开箱即用的SimpleInjectorControllerActivator。在ASP.NET Core中,控制器激活器是完美的拦截点,由于类似OWIN的管道,作用域可以很容易地包裹在请求周围。因此,对于ASP.NET Core,建议的做法是使用控制器激活器作为拦截点。

最新更新