上一篇介绍了依赖注入容器在复杂场景下的使用,这一篇主要介绍推荐的实践用法,以及如何注入和使用第三方容器。
1. 推荐实践
Action 注入依赖service
在Controller中,我们习惯于将所有需要的一股脑的注入到controller的constrcutor中,但实际上,有些service,我们只在个别的Action方法中用到,这样的service注入在了constrcutor中,会导致每次请求的时候都实例化一次这个service,哪怕并不需要。对于这样的service,推荐的做法是在Action 方法中声明通过依赖注入容器帮助我们实例化出来。
示例:
[Route("api/[controller]")] [ApiController] public class CurrentWeatherController : ControllerBase { private readonly IMemoryCache _memoryCache; public CurrentWeatherController(IMemoryCache memoryCache) { _memoryCache = memoryCache; } [Route("A")] public Get() { // 业务逻辑 } [Route("B")] public Get([FromServices] IBservice bservice) { // 业务逻辑 只在此 路由中使用 bservice } }
Middleware 注入依赖service
middleware是在host主机启动时候就已经实例化好的,因此对于一些非singleton得service,如果将那些service注入到middleware得依赖方法中,就会导致middleware捕获一些scope和transient生命周期得service,进而造成不可预测的风险。
对于非singleton 得service,在middleware得注入方法推荐:
services.AddScoped<IUserManager, UserManager>(); ------------------------------------ public class LastRequestMiddleware { private readonly RequestDelegate _next; public LastRequestMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context, UserManager userManager) { // 业务逻辑 await _next(context); } }
使用依赖注入替代GetService
不推荐得做法
推荐使用方式
public class MyClass { private readonly IOptionsMonitor<MyOptions> _optionsMonitor; public MyClass(IOptionsMonitor<MyOptions> optionsMonitor) { _optionsMonitor = optionsMonitor; } public void MyMethod() { var option = _optionsMonitor.CurrentValue.Option; ... } }
2. Autofac 集成及使用场景
不同版本的autofac集成参考 https://autofac.readthedocs.io/ 官网
这里以.net core3+ 为例,因为通用主机概念的引入,在3.0+的版本引入autofac和以前有一些不同。通过 UseServiceProviderFactory 来注入 AutofacServiceProviderFactory 。
var host = Host.CreateDefaultBuilder(args) .UseServiceProviderFactory(new AutofacServiceProviderFactory()) .ConfigureWebHostDefaults(webHostBuilder => { webHostBuilder .UseStartup<Startup>(); }) .Build();
在startup.cs 中,和默认的container类似,autofac有一个 ConfigureContainer 的方法,允许你在这个方法内部注册你的services。
public void ConfigureServices(IServiceCollection services) { services.AddOptions(); } public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterModule(new MyApplicationModule()); } .........
具体的使用方法放在下一篇中,因为autofac的功能确实很强大,这里进行一下抛砖引玉,autofac可以做哪些?
1. 更宽泛的生命周期管理,它可以指定scope的name来保证service在该scope里共享实例;
2. module的注册方式及声明式的注册;相比于默认的DI container, 它支持json的声明方式及assembly的加载,减少了频繁添加修改service的注册信息的工作;
3. 自动的属性注入;
4. autofac 实现面向切片编程; (有助于我们将通用的处理逻辑和业务逻辑相分离,当然也不要滥用,对于一些通过filterattribute, authorazition attibute本身可以实现的,不需要为了使用而使用)。
下一篇会重点关注这个autofac的实际开发应用场景,并且区分什么时候应该使用。
------------------------
正如大佬们所说“我只是一个小学生”, 欢迎大家讨论交流,指出不足以进步更好,谢谢!