为了账号安全,请及时绑定邮箱和手机立即绑定

asp.net core 系列 4 注入服务的生存期

标签:
C#

一.服务的生存期

  在容器中每个注册的服务,根据程序应用需求都可以选择合适的服务生存期,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中只实例化一次,常见的单例模式。

 

  参考文献:

    官方文档:ASP.NET Core 

原文出处:https://www.cnblogs.com/MrHSR/p/10234436.html  

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消