如何在ASP.NET Core应用中实现与第三方IoC/DI框架的整合?

我们知道整个ASP.NET Core建立在以ServiceCollection/ServiceProvider为核心的DI框架上,它甚至提供了扩展点使我们可以与第三方DI框架进行整合。对此比较了解的读者朋友应该很清楚,针对第三方DI框架的整合可以通过在定义Startup类型的ConfigureServices方法返回一个ServiceProvider来实现。但是真的有这么简单吗?

一、ConfigureServices方法返回的ServiceProvider貌似没有用!?

我们可以通过一个简单的实例来说明这个问题。我们先定义了如下这个一个MyServiceProvider,它实际上是对另一个ServiceProvider的封装。简单起见,我们利用一个字典来保存服务接口与实现类型的映射关系,这个关系可以通过调用Registe方法来注册。在提供服务实例的GetService方法中,如果提供的服务类型已经被注册,我们会创建并返回对应的实例对象,否则我们将利用封装的这个ServiceProvider来提供服务。为了确保服务实例能够被正常回收,如果服务类型实现了IDisposable接口,我们会将它添加到通过字段_disposables表示的集合中。当MyServiceProvider的Dispose方法被调用的时候,提供的这些服务实例的Dispose方法会被调用。

   1: public class MyServiceProvider : IServiceProvider,IDisposable
   2: {
   3:     private IServiceProvider        _innerServiceProvider;
   4:     private Dictionary<Type,Type>  _services;
   5:     private List<IDisposable>       _disposables;
   6:  
   7:     public MyServiceProvider(IServiceProvider innerServiceProvider)
   8:     {
   9:         _innerServiceProvider  = innerServiceProvider;
  10:         this._services         = new Dictionary<Type,Type>();
  11:         _disposables           = new List<IDisposable>();
  12:     }
  13:  
  14:  
  15:     public MyServiceProvider Register<TFrom,TTo>() where TTo: TFrom,new()
  16:     {
  17:         _services[typeof(TFrom)] = typeof(TTo);
  18:         return this;
  19:     }
  20:  
  21:     object GetService(Type serviceType)
  22:     {
  23:         Type implementation;
  24:         if (_services.TryGetValue(serviceType,1)">out implementation))
  25:         {
  26:             object service = Activator.CreateInstance(implementation);
  27:             IDisposable disposbale = service as IDisposable;
  28:             if (null != disposbale)
  29:             {
  30:                 _disposables.Add(disposbale);
  31:             }
  32:             return service;
  33:         }
  34:         return _innerServiceProvider.GetService(serviceType);
  35:     }
  36:  
  37:     void Dispose()
  38:     {
  39:         (_innerServiceProvider as IDisposable)?.Dispose();
  40:         foreach (var it in _disposables)
  41:         {
  42:             it.Dispose();
  43:         }
  44:         _disposables.Clear();
  45:     }
  46: }

我们按照如下的方式在一个ASP.NET Core应用中使用MyServiceProvider。如下面的代码片断中,在注册的Starup类型中,我们让ConfigureServices方法返回一个MyServiceProvider对象。服务接口IFoobar和实现类型Foobar之间的映射注册在这个MyServiceProvider对象上。在处理请求的时候,我们利用当前HttpContext对象的RequestServices属性得到为请求处理提供服务的ServiceProvider,并试图利用它得到注册的IFoobar服务。

static void Main(string[] args)
   5:         new WebHostBuilder()
   7:             .UseStartup<Startup>()
   9:             .Run();
  11: }
  13: class Startup
public IServiceProvider ConfigureServices(IServiceCollection services)
  18:             .Register<IFoobar,Foobar>();
  23:         app.UseDeveloperExceptionPage()
  25:     }
  27: interface IFoobar { }
internal class ServiceScope : IServiceScope
   4:  
   6:     {
   8:     }
  10:     {
  14:       15:     {
  17:     }
  19:  
  21: {
  23:       24:  
  27:         _innerServiceFactory = innerServiceFactory;
  29:     }
  31:     {
  33:     }
public MyServiceProvider(IServiceProvider innerServiceProvider,1)">   5:         _innerServiceProvider = innerServiceProvider;
   7:         _disposables =    9:  
  12:         if (serviceType == typeof(IServiceScopeFactory))
  14:             IServiceScopeFactory innerServiceScopeFactory = _innerServiceProvider.GetRequiredService<IServiceScopeFactory>();
  17:         ...        
  19:     ...