ASP.NET 通过 属性 或 setter 方法进行核心 MVC 依赖注入

ASP.NET Core MVC Dependency Injection via property or setter method

它有been well documented,如何将依赖项注入服务。

问题:但是在ASP.NET Core 2.0中是否(已经)可以让系统的DI机制自动注入将服务转化为方法或转化为 属性?

旁注:在 PHP-Symfony 中,此模式称为 setter injection.

示例: 假设我的项目中的所有控制器都有一个公共的 MyBaseController class,我希望将一个服务(例如 UserManager 服务)注入 MyBaseController,以后可以在所有子控制器中访问该服务.我可以使用构造函数注入将服务注入子 class 并通过 base(userManager) 将其传递给父。但是必须在所有控制器的所有子构造函数中执行此操作非常乏味。

所以我想在 MyBaseController 中有一个像这样的 setter:

public abstract class MyBaseController : Controller
{
  public UserManager<User> userManager { get; set; }

  // system should auto inject UserManager here
  public void setUserManager(UserManager<User> userManager) {
    this.userManager = userManager;
  }
}

...所以我不必在每个子构造函数中都执行以下操作,只是为了将依赖项传递给父构造函数:

public class UsersController : MyBaseController
{
  public ChildController(UserManager<User> userManager) : base(userManager) {}

更新: 的答案是我想要实现的,但是问题是针对 ASP.NET Core 1.0 提出的,我想知道 [= 中是否添加了任何解决方案43=] 核心 2.0.

一般来说,避免非构造函数 DI 是一个很好的建议,因为它被认为有点反模式,在此 .

中对此进行了很好的讨论

使用 aspnet core 中的默认 Microsoft.Extensions.DependencyInjection 容器,答案是否定的,但如果您确定确实需要此功能,则可以换成更强大的东西,例如 autofac (which has property injection)

你有两种DI

  1. 必填,对象初始化需要注入,然后在构造函数中设置注入。
  2. 可选,需要注入才能执行。

如果 DI 做得好,你可以在没有注入系统的情况下进行单元测试,如果所有注入都在 ctor 中,那么你将破坏每个单元测试,每次都白费。

因此 ctor 中的所有注入都违反了 open/close 原则。

还有一点是DI是接口实现或者模块public部分,这个实现下的对象都是手动初始化的

所以setter还不错因为有接口隐藏

您可以使用 Quickwire 使用内置 DI 容器 (Microsoft.Extensions.DependencyInjection) 执行 setter 注入。与 Autofac 不同,这不是一个新的 DI 容器,它只是扩展了默认容器。

让它发挥作用:

  1. 将此添加到 ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
    // Activate controllers using the dependency injection container
    services.AddControllers().AddControllersAsServices();

    services.ScanCurrentAssembly();

    // ...
    // Register your other services
}

默认情况下,ASP.NET Core 将通过直接实例化控制器而不通过 DI 容器来激活它们。幸运的是,这种行为可以很容易地被覆盖以强制 ASP.NET 核心使用依赖注入来解析控制器。这就是 services.AddControllers().AddControllersAsServices() 所做的。

ScanCurrentAssembly 是让 Quickwire 搜索在您的程序集中声明的服务并注册它们(其中将包括您的控制器)所必需的。

  1. [RegisterService]
  2. 装饰你的子控制器
[RegisterService(ServiceLifetime.Transient)]
public class ChildController : MyBaseController
{
    // ...
}

这将使您的 ChildController 在步骤 1 中调用 ScanCurrentAssembly 时被发现。

  1. 装饰setter
public abstract class MyBaseController : Controller
{
    [InjectService]
    public UserManager<User> UserManager { get; private set; }
}

现在,您的子控制器中的 UserManager 属性 将从依赖项注入容器中自动设置。