asp.net core 系列 4 注入服务的生存期
一.服务的生存期
在容器中每个注册的服务,根据程序应用需求都可以选择合适的服务生存期,asp.net core 服务有三种生存期配置:
(1) transient:暂时生存期,在每次请求时被创建。 这种生存期适合轻量级的,无状态的服务。
(2) scoped: 作用域生存期,在每次请求被创建一次。
(3) singleton: 单例生存期,在它们第一次被请求时创建。每个后续请求将使用相同的实例。如果应用程序需要单例行为,建议让服务容器管理服务的生命周期,而不是在自己的类中实现单例模式。
1.1 演示案例
为了演示生存期和注册选项之间的差异, 以下服务接口,任务是演示标识符 operationid
的操作值变化。 根据为以下接口配置操作服务的生存期的方式,容器在类请求时提供相同或不同的服务实例:
public interface ioperation { guid operationid { get; } } //用于演示暂时生存期 public interface ioperationtransient : ioperation { } //用于演示作用域生存期 public interface ioperationscoped : ioperation { } //用于演示单例生存期 public interface ioperationsingleton : ioperation { } //用于演示单例中空guid public interface ioperationsingletoninstance : ioperation { }
上面四种服务接口在 operation 类中实现。 调用 operation类时将自动生成一个 guid(如果实例化operation类时没有指定guid),下面是operation类的实现:
public class operation : ioperationtransient, ioperationscoped, ioperationsingleton, ioperationsingletoninstance { /// <summary> /// 构造方法中生成guid,在实例化类时 /// </summary> public operation() : this(guid.newguid()) { } public operation(guid id) { operationid = id; } /// <summary> /// 获取guid /// </summary> public guid operationid { get; private set; } }
再注册一个 operationservice 服务,该服务取决于每个其他 operation 类型。 当通过依赖关系注入请求 operationservice 时,它将接收每个服务的新实例或基于从属服务(operation )的生存期的现有实例。operationservice 服务作用就是第二次调用 operation类,查看operation类实例的作用域变化。
public class operationservice { public ioperationtransient transientoperation { get; } public ioperationscoped scopedoperation { get; } public ioperationsingleton singletonoperation { get; } public ioperationsingletoninstance singletoninstanceoperation { get; } public operationservice( ioperationtransient transientoperation, ioperationscoped scopedoperation, ioperationsingleton singletonoperation, ioperationsingletoninstance instanceoperation) { transientoperation = transientoperation; scopedoperation = scopedoperation; singletonoperation = singletonoperation; singletoninstanceoperation = instanceoperation; } }
(1) 如果在请求时创建了临时服务(transient),则 ioperationtransient 服务的 operationid 与 operationservice 的 operationid 不同。 operationservice 将接收 ioperationtransient 类的新实例。 新实例将生成一个不同的 operationid。
(2) 如果按请求创建有作用域的服务(scoped),则 ioperationscoped 服务的 operationid 与请求中 operationservice 的该 id 相同。 在请求中,两个服务共享不同的 operationid 值。
(3) 如果单一实例服务(singleton),则只创建一次 并在所有请求和所有服务中使用,则 operationid 在所有服务请求中保持不变。
下面是在 startup.configureservices 服务容器中注册,指定服务的生存期:
services.addtransient<ioperationtransient, operation>(); services.addscoped<ioperationscoped, operation>(); services.addsingleton<ioperationsingleton, operation>(); services.addsingleton<ioperationsingletoninstance>(new operation(guid.empty)); services.addtransient<operationservice, operationservice>();
为了演示各个请求中的对象生存期。 下面示例应用 index页面,请求 ioperation 类型和 operationservice。 然后查看operation类属性operationid 值的变化:
public class indexmodel : pagemodel { public operationservice operationservice { get; } public ioperationtransient transientoperation { get; } public ioperationscoped scopedoperation { get; } public ioperationsingleton singletonoperation { get; } public ioperationsingletoninstance singletoninstanceoperation { get; } public indexmodel( operationservice operationservice, ioperationtransient transientoperation, ioperationscoped scopedoperation, ioperationsingleton singletonoperation, ioperationsingletoninstance singletoninstanceoperation) { operationservice = operationservice; transientoperation = transientoperation; scopedoperation = scopedoperation; singletonoperation = singletonoperation; singletoninstanceoperation = singletoninstanceoperation; } public string bindguidmsg { get; set; } public void onget() { bindguidmsg += "ioperation操作: <br/> "; bindguidmsg += "暂时性:" + transientoperation.operationid.tostring() + "</br>"; bindguidmsg += "有作用域:" + scopedoperation.operationid.tostring() + "</br>"; bindguidmsg += "单一实例:" + singletonoperation.operationid.tostring() + "</br>"; bindguidmsg += "实例:" + singletoninstanceoperation.operationid.tostring() + "</br>"; bindguidmsg += "</br></br></br>operationservice操作:</br>"; bindguidmsg += "暂时性:" + operationservice.transientoperation.operationid.tostring() + "</br>"; bindguidmsg += "有作用域:" + operationservice.scopedoperation.operationid.tostring() + "</br>"; bindguidmsg += "单一实例:" + operationservice.singletonoperation.operationid.tostring() + "</br>"; bindguidmsg += "实例:" + operationservice.singletoninstanceoperation.operationid.tostring() + "</br>"; } }
<div > @{ @html.raw(@model.bindguidmsg); } </div>
第一次index页面请求:
ioperation 操作:
暂时性:8ef874a3-743d-4288-98d4-3df126cd940d
有作用域:256ff050-f469-4ea3-8dde-16cdd3087c83
单一实例:d2caf297-a9b1-4dcf-adda-c68e46fe0741
实例:00000000-0000-0000-0000 -000000000000
operationservice操作:
暂时性:5411fd0d-f2e1-4885-beee-2d7ccf48dceb
有作用域:256ff050-f469-4ea3-8dde-16cdd3087c83
单一实例:d2caf297-a9b1-4dcf-adda-c68e46fe0741
实例:00000000-0000-0000- 0000-000000000000
第二次index页面请求:
ioperation操作:
暂时性:e685fd0e-d2e0-4900-9eff-e6bc41cd2f80
有作用域:ca233b49-8326-4a7e-8ee4-6993d70786ed
单一实例:d2caf297-a9b1-4dcf-adda-c68e46fe0741
实例:00000000-0000-0000-0000-000000000000
operationservice操作:
暂时性:db89be00-c3b7-4f99-bead-5be693ccc2c0
有作用域:ca233b49-8326-4a7e-8ee4-6993d70786ed
单一实例:d2caf297-a9b1-4dcf-adda-c68e46fe0741
实例:00000000-0000-0000-0000-000000000000
下面再总结一下:
(1)暂时性注册的服务,每次调用服务都会是一个新的服务对象实例。相当于在indexmodel类的局部(方法或属性中)实例化一个依赖对象operation类,伪代码是:
public class indexmodel { public void onget() {
//加载index页时,实例化了二次operation类
//第一次 operationservice operationservice=new operationservice();
//第二次
ioperationtransient transientoperation =new operation(); } }
(2)作用域注册的服务,一次请求内(加载一次index页)对象实例是相同的,但每次请求会产生一个新实例。相当于在indexmodel类的全局中实例化一次依赖对象operation类,伪代码是:
operationservice operationservice = null; public indexmodel() { operationservice = new operationservice(); operationservice.scopedoperation = new operation(); } public void onget() { operationservice.scopedoperation.operationid; ioperationscoped operationscoped=operationservice.scopedoperation; operationscoped.operationid }
(3)单例注册的服务,实例对象对每个对象和每个请求都是相同的。相当于在整个应用application中只实例化一次,常见的单例模式。
参考文献:
上一篇: 浅谈JackSon的几种用法
推荐阅读
-
ASP.NET Core依赖注入系列教程之服务的注册与提供
-
ASP.NET Core 2.2 WebApi 系列【三】AutoFac 仓储接口的依赖注入
-
ASP.NET Core Web 应用程序系列(一)- 使用ASP.NET Core内置的IoC容器DI进行批量依赖注入(MVC当中应用)
-
asp.net core 系列 4 注入服务的生存期
-
ASP.NET Core依赖注入系列教程之服务的注册与提供
-
asp.net core系列 58 IS4 基于浏览器的JavaScript客户端应用程序
-
ASP.NET Core 2.2 WebApi 系列【三】AutoFac 仓储接口的依赖注入
-
ASP.NET Core Web 应用程序系列(三)- 在ASP.NET Core中使用Autofac替换自带DI进行构造函数和属性的批量依赖注入(MVC当中应用)
-
ASP.NET Core Web 应用程序系列(一)- 使用ASP.NET Core内置的IoC容器DI进行批量依赖注入(MVC当中应用)
-
Asp.Net Core 实现服务的批量注册注入