如何在netcore下,愉快的使用IServiceProvider

之前一直做dotnet framework开发,依赖注入使用Autofac,Autofac的一般用法是服务启动时,将用到的接口、实现类名注入进去,

然后在服务其他地方如果使用该类时,直接在Container里面Resolve出来即可。

 

后来使用netcore 2.1,框架本身使用了Microsoft.Extensions.DependencyInjection,是服务启动时,把需要注入的服务通过

public void ConfigureServices(IServiceCollection services)

实现依赖注入,在服务其他地方通过构造函数把服务实例化出来,然后实现具体方法的调用。

 

期初,因为场景比较简单,用起来比较舒服,后来随着业务复杂,就面临了一些挑战:

1)在服务的某个方法中,不想通过构造函数,现在想使用已经注入的接口方法,咋办?

为了解决这个问题,我们引入了IHttpContextAccessor(web服务),在IHttpContextAccessor里面有HttpContext,

在HttpContext里面有个RequestServices就是IServiceProvider类型,里面有我们想要的已经注入的服务:

 public abstract class ControllerBase : Controller
 {
    protected ControllerBase(IMediator mediator, ILogger logger, IHttpContextAccessor accessor)
     {
        var configuration = accessor.HttpContext.RequestServices.GetRequiredService<IConfigurationManager>();
     }
 }

 PS:使用HttpContext里面的RequestServices是有局限的,比如单元测试怎么写?(其实还是仿web的初始化,本次不讨论)

上面的使用HttpContext里面的RequestServices解决了一些问题,但是后来又遇到问题了

2)异步编程,Handler里面处理的逻辑比较耗时,所以我们打算把里面的逻辑抽出来使用异步方式,然后立刻返回结果,

立刻返回结果导致HttpContext.RequestServices变成了null,所以在异步调用逻辑中用到RequestServices的地方全部报错。

 

根据这个问题,我们在common项目里面增加ServiceLocator类:

public class ServiceLocator
    {
        public static IServiceProvider Services { get; private set; }
        public static void SetServices(IServiceProvider services)
        {
            Services = services;
        }
    }

 然后在 public void ConfigureServices(IServiceCollection services)

 方法里面使用

 // 将注入放在全局变量里维护
 ServiceLocator.SetServices(serviceProvider);

 PS:尽量在该方法的最下面使用这个赋值。

然后在你服务中的其他位置使用它拿到已经注入的接口

  注意:在ServiceLocator里面使用的接口应该都是只读的实例,这样就不会产生更新操作,导致线程不安全的问题

 

posted @ 2019-11-28 10:49  DarryRing  阅读(8419)  评论(8编辑  收藏  举报