使用Simple Injector和IHttpControllerActivator解决ASP.NET Web API中的依赖项

Tho*_*mas 8 c# dependency-injection simple-injector 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.
}
Run Code Online (Sandbox Code Playgroud)

这里的要点是注册Web Api控制器并设置自定义依赖项解析器.

但是,我刚刚阅读了Mark Seemann关于如何在Asp.Net Web Api中配置依赖注入的这些文章:

从这些文章中,我了解到有一个比IDependencyResolver解决Web Api依赖关系更好的选择.另一个选择是创建一个实现,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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

GlobalConfiguration.Configuration.DependencyResolver =
    new SimpleInjectorWebApiDependencyResolver(container);
Run Code Online (Sandbox Code Playgroud)

通过这一行:

GlobalConfiguration.Configuration.Services.Replace(
    typeof(IHttpControllerActivator),
    new SimpleInjectorControllerActivator(container));
Run Code Online (Sandbox Code Playgroud)

我想知道它的实现IHttpControllerActivator是否有效,以及这种方法是否有效并且与普通方法一样好?

Ste*_*ven 3

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

请注意不要在同一应用程序中同时使用 theSimpleInjectorWebApiDependencyResolver和 the 。SimpleInjectorControllerActivator两者都以 an 开头ExecutionContextScope,这可能会导致同一 Web 请求中有两个作用域,因此它们是互斥的。

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

然而,Simple Injector Web API 集成项目通过依赖解析器防止了这个问题,null如果请求的服务是 API 控制器(从而隐式破坏了 的契约),则永远不会返回(而是抛出异常IDependencyResolver)。

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

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

过去,我们决定为 DI 使用适配器IDependencyResolver,主要是因为这是所有 DI 容器的常见做法。我对这个决定有些后悔,但SimpleInjectorDependencyResolver现在使用通常是将 Simple Injector 插入 Web API 的最简单方法。我们SimpleInjectorControllerActivator也考虑添加一个,但这对大多数用户来说没有实际好处,而我们仍然必须记录何时使用什么。所以我们决定坚持使用依赖解析器适配器;如您所见,任何需要它的人都可以轻松创建激活器的适配器。

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