使用Simple Injector和IHttpControllerActivator

时间:2016-04-14 03:27:47

标签: c# asp.net-web-api dependency-injection simple-injector

我目前正在使用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.
}

这里的要点是注册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);
    }
}

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

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

这一行:

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

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

1 个答案:

答案 0 :(得分:3)

是的,您的实施有效。

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

在依赖项解析程序上使用控制器激活器的一般优点是依赖项解析程序合同强制适配器在无法创建服务时返回null。这是开发人员遇到的一个非常常见的问题,它经常导致令人困惑的controller does not have a default constructor异常。使用IHttpControllerActivator时不存在此问题,因为合同会强制您返回值或抛出异常。

然而,Simple Injector Web API集成项目通过永远不返回null(但抛出异常)来防止依赖解析器出现此问题,以防请求的服务是API控制器(从而隐式地破坏{ {1}}合同)。

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

Mark Seemann的一个论点是,只要你的components don't require this context during construction,就很难传递上下文,这是一个非常有效的观点。但是这不是您在使用Simple Injector时会遇到的问题,因为有extension method可以帮助您访问request.GetDependencyScope()。因此,虽然HttpRequestMessage抽象不是为获取上下文信息而设计的,但有一些方法可以获取此上下文信息。

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

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