即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

.net core依赖注入的封装

微信 dotNET跨平台 22℃ 0评论

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

这样我们就可以不再像以前一样,需要引入第三方的Untiy、Autofac、Castle等DI组件了。

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

  • Singleton:ServiceProvider创建的服务实例保存在作为根节点的ServiceProvider上,所有具有同一根节点的所有ServiceProvider提供的服务实例均是同一个对象。适合于单例模式。

  • Scoped:ServiceProvider创建的服务实例由自己保存,所以同一个ServiceProvider对象提供的服务实例均是同一个对象。 可以简单的认为是每请求(Request)一个实例。

  • Transient:针对每一次服务提供请求,ServiceProvider总是创建一个新的服务实例。 每次访问时被创建,适合轻量级的,无状态的服务。

这个具体说起来就太多了,还是查阅相关材料吧J

 

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

public void ConfigureServices(IServiceCollection services)
{
services.AddScoped();
}

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

 

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

public partial class OperLogAppService : IOperLogAppService
{
private IOperLogRepository service;
public OperLogAppService(IOperLogRepository service)
{
this.service = service;
}

public void Write(OperLogDto operLogDto)
{
this.service.Insert(operLogDto.AsInfo());
}
}

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

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

我们的做法是,功能模块都有一个自注册的类。这个自注册的类会将功能模块中所有的仓储类、逻辑服务类等都注册进DI容器中。Startup.cs会自动查找所有功能模块中的自注册类,然后将相关内容注册进DI容器中。这样就可以做到,每增加一个模块,只需要将该模块的应用程序集Dll复制到系统的运行目录就行了,其他的系统帮你搞定。

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

public interface IServiceRegister
{
///
/// 注册
///
void Register(IServiceCollection services);
}

 

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

 public class CommonServiceRegister : IServiceRegister
{
public void Register(IServiceCollection services)
{
services.AddDbContext(option =>
option.UseDb(services.BuildServiceProvider()),
ServiceLifetime.Scoped);
services.AddScoped();
services.AddScoped();
services.AddScoped();
services.AddScoped

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

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

 IEnumerable serviceList = ReflectionHelper.GetSubTypes();
foreach (Type type in serviceList)
{
IServiceRegister register = ReflectionHelper.CreateInstance(type)
as IServiceRegister;
register.Register(services);

}

 

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

原文地址:http://www.cnblogs.com/BenDan2002/p/6087893.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

转载请注明:CodingBlog » .net core依赖注入的封装

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情
(5)个小伙伴在吐槽
  1. 非常感谢
    Dob朱2017-02-27 23:19 回复
  2. /强/强/强/强
    Lin2017-02-27 23:29 回复
  3. 如果既想维护老得项目,又想尝试Core而且只有一台开发机,在不装虚拟机得情况下如何实现呢?
    汤国臣2017-02-27 23:57 回复
  4. 内置依赖注入是ASP.NET Core自带的,不是.Net Core
    李争(Michael)2017-02-27 23:58 回复
  5. /强/强 .Net core默认包含ioc组件可见他的重要性,而且比autofac好用,不用自己构建container了,就是不知道和三方ioc比起来他的性能咋样/憨笑/憨笑
    蜜汁哈士奇2017-02-28 00:06 回复