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

一.服务的生存期

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

 参考文献:

    官方文档:ASP.NET Core 

相关文章
相关标签/搜索