zoukankan      html  css  js  c++  java
  • 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中只实例化一次,常见的单例模式。

      参考文献:

        官方文档:ASP.NET Core 

    欢迎添加个人微信号:Like若所思。

    欢迎关注我的公众号,不仅为你推荐最新的博文,还有更多惊喜和资源在等着你!一起学习共同进步!

  • 相关阅读:
    解决方案下显示的网站名称被追加编号的问题解决方法
    sql server 2008 报表服务器(sql server 2008 report service)中如何固定行或者列
    如何通过参数来切换图表和数据
    饼图中如何将一定比例的小切片收集在一起
    饼图图例中显示百分比值
    如何根据条件隐藏列
    饼图上如何显示百分比值
    负载均衡
    在UTF8页中接收和使用以GB2312方式进行URL编码的中文数据
    ASP 格式化显示时间为几个月,几天前,几小时前,几分钟前,或几秒前
  • 原文地址:https://www.cnblogs.com/cool2feel/p/11508026.html
Copyright © 2011-2022 走看看