【问题标题】:Resolve dependencies in ASP.NET Web API with Simple Injector and IHttpControllerActivator使用 Simple Injector 和 IHttpControllerActivator 解决 ASP.NET Web API 中的依赖关系
【发布时间】:2016-04-14 03:27:47
【问题描述】:

我目前正在使用 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 的实现是否有效,以及这种方法是否有效并且与普通方法一样有效?

【问题讨论】:

  • 我没有发布更新版本,而是使用 SimpleInjectorControllerActivator 的简化版本更新了您的问题。

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


【解决方案1】:

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

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

与依赖解析器相比,使用控制器激活器的一个普遍优势是,当无法创建服务时,依赖解析器合约会强制适配器返回 null。这是开发人员遇到的一个非常常见的问题,并且经常会导致令人困惑的controller does not have a default constructor 异常。使用IHttpControllerActivator 时不存在此问题,因为合约会强制您返回值或抛出异常。

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

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

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

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

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

【讨论】:

  • 谢谢史蒂文!我需要看一下 asp.net 核心框架,因为我想知道这种方法在 asp.net 核心上下文中是否仍然有效?
  • 有没有机会使用简单的注入器将这种方法作为默认的 web api 集成?
  • 在这种特定情况下,如果SimpleInjectorControllerActivator 都以ExecutionContext 开头,那么使用SimpleInjectorWebApiDependencyResolver 的优势是什么?使用ControllerActivator 可以获得哪些使用DependencyResolver 无法获得的context 信息?
  • 事实上,您无法从 IDependencyResolver 获取任何信息...使用 IHttpControllerActivator 实现,您可以访问 HttpRequestMessageHttpControllerDescriptor 类,以便您可以使用 int 进行组合
猜你喜欢
  • 1970-01-01
  • 2014-10-10
  • 1970-01-01
  • 2015-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-01
  • 2017-06-18
相关资源
最近更新 更多