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
- 必填,对象初始化需要注入,然后在构造函数中设置注入。
- 可选,需要注入才能执行。
如果 DI 做得好,你可以在没有注入系统的情况下进行单元测试,如果所有注入都在 ctor 中,那么你将破坏每个单元测试,每次都白费。
因此 ctor 中的所有注入都违反了 open/close 原则。
还有一点是DI是接口实现或者模块public部分,这个实现下的对象都是手动初始化的
所以setter还不错因为有接口隐藏
您可以使用 Quickwire 使用内置 DI 容器 (Microsoft.Extensions.DependencyInjection) 执行 setter 注入。与 Autofac 不同,这不是一个新的 DI 容器,它只是扩展了默认容器。
让它发挥作用:
- 将此添加到
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 搜索在您的程序集中声明的服务并注册它们(其中将包括您的控制器)所必需的。
- 用
[RegisterService]
装饰你的子控制器
[RegisterService(ServiceLifetime.Transient)]
public class ChildController : MyBaseController
{
// ...
}
这将使您的 ChildController
在步骤 1 中调用 ScanCurrentAssembly
时被发现。
- 装饰setter
public abstract class MyBaseController : Controller
{
[InjectService]
public UserManager<User> UserManager { get; private set; }
}
现在,您的子控制器中的 UserManager
属性 将从依赖项注入容器中自动设置。
它有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) {}
更新:
一般来说,避免非构造函数 DI 是一个很好的建议,因为它被认为有点反模式,在此
使用 aspnet core 中的默认 Microsoft.Extensions.DependencyInjection 容器,答案是否定的,但如果您确定确实需要此功能,则可以换成更强大的东西,例如 autofac (which has property injection)。
你有两种DI
- 必填,对象初始化需要注入,然后在构造函数中设置注入。
- 可选,需要注入才能执行。
如果 DI 做得好,你可以在没有注入系统的情况下进行单元测试,如果所有注入都在 ctor 中,那么你将破坏每个单元测试,每次都白费。
因此 ctor 中的所有注入都违反了 open/close 原则。
还有一点是DI是接口实现或者模块public部分,这个实现下的对象都是手动初始化的
所以setter还不错因为有接口隐藏
您可以使用 Quickwire 使用内置 DI 容器 (Microsoft.Extensions.DependencyInjection) 执行 setter 注入。与 Autofac 不同,这不是一个新的 DI 容器,它只是扩展了默认容器。
让它发挥作用:
- 将此添加到
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 搜索在您的程序集中声明的服务并注册它们(其中将包括您的控制器)所必需的。
- 用
[RegisterService]
装饰你的子控制器
[RegisterService(ServiceLifetime.Transient)]
public class ChildController : MyBaseController
{
// ...
}
这将使您的 ChildController
在步骤 1 中调用 ScanCurrentAssembly
时被发现。
- 装饰setter
public abstract class MyBaseController : Controller
{
[InjectService]
public UserManager<User> UserManager { get; private set; }
}
现在,您的子控制器中的 UserManager
属性 将从依赖项注入容器中自动设置。