4.6 .net core依赖注入的封装

如今流行的系统通常都采用依赖注入的实现方式,利用DI容器来直接获取所用到的类/接口的实例。.net core也同样采用DI的方式,提供了DI容器的接口IServiceCollection,并提供了基于该接口的缺省实现ServiceCollection。 html

这样咱们就能够再也不像之前同样,须要引入第三方的Untiy、Autofac、Castle等DI组件了。 数据库

在.net core源码的ServiceCollectionExtensions的实现中,有三个注册的方法AddScoped、AddSingleton、AddTransient。这其中的三个选项(Singleton、Scoped和Transient)体现三种对服务对象生命周期的控制形式。 框架

  • Singleton:ServiceProvider建立的服务实例保存在做为根节点的ServiceProvider上,全部具备同一根节点的全部ServiceProvider提供的服务实例均是同一个对象。适合于单例模式。
  • Scoped:ServiceProvider建立的服务实例由本身保存,因此同一个ServiceProvider对象提供的服务实例均是同一个对象。 能够简单的认为是每请求(Request)一个实例。
  • Transient:针对每一次服务提供请求,ServiceProvider老是建立一个新的服务实例。 每次访问时被建立,适合轻量级的,无状态的服务。

这个具体提及来就太多了,仍是查阅相关材料吧Jide

 

有了DI容器,咱们在使用时,能够简单的在Startup.cs程序中编写上注册语句,下面以操做日志的仓储类为例: 工具

1         public void ConfigureServices(IServiceCollection services)
2         {
3             services.AddScoped<IOperLogRepository, OperLogRepository>();
4         }

 第一个泛型类型表示将要从容器中请求的类型(一般是一个接口)。第二个泛型类型表示将由容器实例化而且用于完成这些请求的具体类型。post

 

咱们在操做日志的逻辑服务类使用操做日志的仓储时,就这样写: ui

 1     public partial class OperLogAppService : IOperLogAppService
 2     {
 3         private IOperLogRepository service;
 4 
 5         public OperLogAppService(IOperLogRepository service)
 6         {
 7             this.service = service;
 8         }
 9 
10         public void Write(OperLogDto operLogDto)
11         {
12             this.service.Insert(operLogDto.AsInfo());
13         }
14     }

 

系统会在建立OperLogAppService的实例时,会自动建立IOperLogRepository在DI容器中注册OperLogRepository类的实例。 this

然而这种方式在框架中是有些不方便的。咱们知道,框架要求的是可扩展,可配置,在新增系统功能模块时,还须要手工修改程序,在Startup.cs的ConfiguraeService中增长注册(就算把全部注册移到一个独立的方法中也是同样),就如同第一个代码写的同样,包括注册仓储类、注册逻辑服务类等等。而后编译,再发布运行。每增长、修改一个模块,都须要整个系统编译、发布,对运行中的系统影响仍是挺大的。 url

咱们的作法是,功能模块都有一个自注册的类。这个自注册的类会将功能模块中全部的仓储类、逻辑服务类等都注册进DI容器中。Startup.cs会自动查找全部功能模块中的自注册类,而后将相关内容注册进DI容器中。这样就能够作到,每增长一个模块,只须要将该模块的应用程序集Dll复制到系统的运行目录就好了,其余的系统帮你搞定。 spa

按照上述思路,首先是建一个自注册的类。这个类都抽象出一个接口IServiceRegister

1     public interface IServiceRegister
2     {
3         /// <summary>
4         /// 注册
5         /// </summary>
6         void Register(IServiceCollection services);
7     }

 

 

咱们以通用模块为例子,自注册的类应该是这样的。

 1     public class CommonServiceRegister : IServiceRegister
 2     {
 3         public void Register(IServiceCollection services)
 4         {
 5             services.AddDbContext<CommonDbContext>(option => option.UseDb<CommonDbContext>(services.BuildServiceProvider()), ServiceLifetime.Scoped);
 6 
 7             services.AddScoped<IParaReferRepository, ParaReferRepository>();
 8             services.AddScoped<IParaReferAppService, ParaReferAppService>();
 9             services.AddScoped<ISystemParameterRepository, SystemParameterRepository>();
10             services.AddScoped<ISystemParameterAppService, SystemParameterAppService>();
11 12         }
13     }

 

这个类中service.AppScoped注册的是仓储层和逻辑层接口对应的实现类,咱们这里只是列出了系统参数和引用参数的注册。对于第一句AddDbContext,请参见:4.4 异构、多数据库的存取组件

为了在Startup.cs中本身查找并调用这些注册类,仍是比较简单的,程序以下:调用ReflectionHelper的GetSubTypes方法,获取全部继承IServiceRegister的实现类,对于每一个实现类,建立实例并将模块的仓储和逻辑服务注册到DI容器中。ReflectionHelper的GetSubTypes方法,请参见:4.1 反射工具

1     IEnumerable<Type> serviceList = ReflectionHelper.GetSubTypes<IServiceRegister>();
2     foreach (Type type in serviceList)
3     {
4         IServiceRegister register = ReflectionHelper.CreateInstance(type) as IServiceRegister;
5 
6         register.Register(services);
7     }

 

.net framework也能够按照上述思路进行,不一样的就是.net framework没有startup.cs,只须要将上面的内容写进global.asax便可,还有一点不一样是IServiceCollection,可使用Unity等DI组件提供的DI容器。

  

面向云的.net core开发框架

相关文章
相关标签/搜索