在容器中每一个注册的服务,根据程序应用需求均可以选择合适的服务生存期,ASP.NET Core 服务有三种生存期配置:ui
(1) Transient:暂时生存期,在每次请求时被建立。 这种生存期适合轻量级的,无状态的服务。this
(2) Scoped: 做用域生存期,在每次请求被建立一次。spa
(3) Singleton: 单例生存期,在它们第一次被请求时建立。每一个后续请求将使用相同的实例。若是应用程序须要单例行为,建议让服务容器管理服务的生命周期,而不是在本身的类中实现单例模式。3d
1.1 演示案例code
为了演示生存期和注册选项之间的差别, 如下服务接口,任务是演示标识符 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类的实现:blog
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中只实例化一次,常见的单例模式。
参考文献: