Asp.Net Core中服务的生命周期选项区别和用法
在做一个小的Demo中,在一个界面上两次调用视图组件,并且在视图组件中都调用了数据库查询,结果发现,一直报错,将两个视图组件的调用分离,单独进行,却又是正常的,寻找一番,发现是配置依赖注入服务时,对于服务的生命周期没有配置得当导致,特此做一次实验来认识三者之间(甚至是四者之间的用法及区别)。
本文demo地址(具体见WebApi控制器中):https://gitee.com/530521314/koInstance.git
一、服务的生命周期
在Asp.Net Core中,内置容器负责管理服务的生命周期,从被依赖注入容器创建开始,等我们调用完服务时,到容器释放该服务的所有实力为止,有几种形式表现:
1、Transient:每次请求服务时,都会创建一个新实例,这种生命周期适合用于轻量级服务(如Repository和ApplicationService服务)。
2、Scoped:为每个HTTP请求创建一个实例,生命周期将横贯整次请求。
3、SingleTon:在第一次请求服务时,为该服务创建一个实例,之后每次请求将会使用第一次创建好的服务。
4、Instance:与SingleTon类似,但在应用程序启动时会将该实例注册到容器中,可以理解为比SingleTon还早存在。
应用程序中相关服务的控制生命周期的方法时通过相应的Add*指定,如下三种,当然还可以通过扩展方法来简化ConfigurationServices方法中所见的代码数量。
services.AddTransient<IApplicationService, ApplicationService>(); services.AddScoped<IApplicationService, ApplicationService>(); services.AddSingleton<IApplicationService, ApplicationService>();
二、代码设计服务生命周期
首先设计一些服务相关的操作接口
1 /// <summary> 2 /// 服务调用 3 /// </summary> 4 public class OperationService : IOperationService 5 { 6 public IOperationTransient _transientOperation { get; } 7 public IOperationScoped _scopedOperation { get; } 8 public IOperationSingleton _singletonOperation { get; } 9 public IOperationInstance _instanceOperation { get; } 10 11 public OperationService(IOperationTransient transientOperation, 12 IOperationScoped scopedOperation, 13 IOperationSingleton singletonOperation, 14 IOperationInstance instanceOperation) 15 { 16 _transientOperation = transientOperation; 17 _scopedOperation = scopedOperation; 18 _singletonOperation = singletonOperation; 19 _instanceOperation = instanceOperation; 20 } 21 22 public List<string> GetGuidString() 23 { 24 return new List<string>() 25 { 26 $"Transient:"+_transientOperation.GetGuid(), 27 $"Scoped:"+_scopedOperation.GetGuid(), 28 $"Singleton:" +_singletonOperation.GetGuid(), 29 $"Instance:"+_instanceOperation.GetGuid(), 30 }; 31 } 32 }聚合服务的实现
在控制器中进行服务注入
1 [Route("api/[controller]")] 2 [ApiController] 3 public class ValuesController : ControllerBase 4 { 5 private readonly IOperationService _operationService; 6 7 public ValuesController(IOperationService operationService) 8 { 9 _operationService = operationService; 10 } 11 12 [HttpGet] 13 [Route(nameof(GetGuidString))] 14 public ActionResult<string> GetGuidString() 15 { 16 return string.Join("\n", _operationService.GetGuidString()); 17 } 18 }
在StartUp中完成服务注入逻辑,这里实现服务注入的方式多种均可。
services.AddTransient<IOperationTransient, OperationTransient>(); services.AddScoped<IOperationScoped, OperationScoped>(); services.AddSingleton<IOperationSingleton, OperationSingleton>();
//应用程序启动时便注入该实例 services.AddSingleton<IOperationInstance>(new OperationInstance(Guid.Empty)); services.AddTransient<IOperationService, OperationService>();
通过访问预期Api地址可以得到不同的四种基础服务的Guid信息,
第一次启动程序(不关闭)发起访问:
第二次(第一次基础上再次访问)发起访问:
可以看见,两次访问下,Singleton和Instance是相同的,都是由应用程序启动时和应用服务加载时决定完毕,Singleton在首次进入服务时进行分配,并始终保持不变,而Instance在应用程序启动时,便将实例注入,进入服务也保持着最先的实例,没有重新分配实例。而Transient和Scoped则进行着变化。
关闭程序,重启,第三次发起访问:
可以见到,Singleton和Instance都发生了变化,也说明了之前在Singleton和Instance处写上的作用。
接下来开始设计Transient和Scoped的不同之处,对于已有代码加上新功能,此次我们只针对Scoped和Transient进行比较。
首先在StartUp中将HttpContextAccessor服务注入,目的是在后期能够针对Scoped获取新的服务实例(尽管两个实例是相同的)。
services.AddHttpContextAccessor();
接着在聚合服务中增加一个方法,用来针对Transient、Scoped测试。
1 /// <summary> 2 /// 获取Transient、Scoped的Guid码 3 /// </summary> 4 /// <returns></returns> 5 List<string> GetTransientAndScopedGuidString();
在聚合服务实现中实现该方法并对已有的服务重新获取实例,得到不同实例下的Guid码。
1 public List<string> GetTransientAndScopedGuidString() 2 { 3 //var tempTransientService = (IOperationTransient)ServiceLocator.Instance.GetService(typeof(IOperationTransient)); 4 5 var tempTransientService = (IOperationTransient)_httpContextAccessor.HttpContext.RequestServices.GetService(typeof(IOperationTransient)); 6 var tempScopedService = (IOperationScoped)_httpContextAccessor.HttpContext.RequestServices.GetService(typeof(IOperationScoped)); 7 8 return new List<string>() 9 { 10 $"原生Transient请求服务:"+_transientOperation.GetGuid(), 11 $"手动Transient请求服务:"+ tempTransientService.GetGuid(), 12 $"原生Scoped请求服务:"+_scopedOperation.GetGuid(), 13 $"手动Scoped请求服务:"+tempScopedService.GetGuid(), 14 }; 15 }
在控制器部分调用该聚合服务即可,并返回相应的结果,本次我返回的结果:
可以看到,对于Scoped来讲,一次请求内多次访问同一个服务是共用一个服务实例的,而对于Transient则是,每次访问都是新的服务实例。
至此,对于这四种服务生命周期算是掌握的差不多了。
参考:
蒋老师文章: https://www.geek-share.com/detail/2670940581.html
田园里的蟋蟀:https://www.geek-share.com/detail/2702491401.html
2018-10-20,望技术有成后能回来看见自己的脚步
- Asp.Net Core中服务的生命周期选项区别与用法详解
- ASP.NET Core 2.0 : 五.服务是如何加载并运行的, Kestrel、配置与环境
- ASP.NET中Get和Post的用法 Request.QueryString,Request.Form,Request.Params的区别 [转]
- asp.net core 开发的https证书服务-agilelabs.net
- 我眼中的ASP.NET Core之微服务
- Asp.net MVC中Html.Partial, RenderPartial, Action,RenderAction 区别和用法
- asp.net core2.0 JWT Bearer 注意添加认证服务
- ASP.NET——Application, Session, Cookie, Viewstate, Cache对象用法和区别
- asp.net <%%>&<%#%>&<%=%>&<%@%>&<%$%>用法区别
- 微服务监控zipkin+asp.net core
- HttpHandler与HttpModule的用处与区别,ASP.NET生命周期
- ASP.NET Application,Session,Cookie和ViewState等对象用法和区别 (转)
- ASP.NET Core身份认证服务框架IdentityServer4(2)-整体介绍
- Asp.net MVC中Html.Partial, RenderPartial, Action,RenderAction 区别和用法
- ASP.NET中Get和Post的用法 Request.QueryString,Request.Form,Request.Params的区别 [转]
- ASP.NET Core的身份认证框架IdentityServer4--(1)服务配置
- ASP.NET状态管理 APPlication,Session,Cookie和ViewState等对象用法和区别
- 在ASP.NET Core中使用Apworks开发数据服务:对HAL的支持
- 【ASP.NET Core】依赖注入高级玩法——如何注入多个服务实现类
- (6)学习笔记 ) ASP.NET CORE微服务 Micro-Service ---- AOP框架