1. 程式人生 > >(3)Asp.Net Core 服務生命週期

(3)Asp.Net Core 服務生命週期

1.前言

在ConfigureServices方法中的容器註冊每個應用程式的服務,Asp.Core都可以為每個應用程式提供三種服務生命週期:
●Transient(暫時):每次請求都會建立一個新的例項。這種生命週期最適合輕量級,無狀態服務。
●Scoped(作用域):在同一個作用域內只初始化一個例項 ,可以理解為每一個請求只建立一個例項,同一個請求會在一個作用域內。
●Singleton(單例):整個應用程式生命週期以內只建立一個例項,後續每個請求都使用相同的例項。如果應用程式需要單例行為,建議讓服務容器管理服務的生命週期,而不是在自己的類中實現單例模式。

2.服務生命週期與註冊選項案例演示

為了演示生命週期和註冊選項之間的差異,請考慮以下介面,將任務表示為具有唯一識別符號 OperationId 的操作。根據以下介面配置操作服務的生命週期的方式,容器在類請求時提供相同或不同的服務例項:

public interface IOperation
{
    Guid OperationId { get; }
}
public interface IOperationTransient : IOperation
{
}
public interface IOperationScoped : IOperation
{
}
public interface IOperationSingleton : IOperation
{
}
public interface IOperationSingletonInstance : IOperation
{
}

上面四種服務介面在 Operation 類中實現。呼叫Operation類時將自動生成一個GUID,下面是Operation類的實現:

public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton, IOperationSingletonInstance
{
    public Operation() : this(Guid.NewGuid())
    {
    }
    public Operation(Guid id)
    {
        OperationId = id;
    }
    public Guid OperationId { get; private set; }
}

再註冊一個OperationService服務例項,當通過依賴關係注入請求 OperationService 例項時,它將接收每個服務的新例項或基於從屬服務(Operation)的生命週期的現有例項。OperationService 服務作用就是第二次呼叫 Operation類,檢視Operation類例項的作用域變化。

public class OperationService
{
    public OperationService(
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance instanceOperation)
    {
        _transientOperation = transientOperation;
        _scopedOperation = scopedOperation;
        _singletonOperation = singletonOperation;
        _singletonInstanceOperation = instanceOperation;
    }
    public IOperationTransient _transientOperation { get; }
    public IOperationScoped _scopedOperation { get; }
    public IOperationSingleton _singletonOperation { get; }
    public IOperationSingletonInstance _singletonInstanceOperation { get; }
}

然後在Startup.ConfigureServices()服務容器中註冊各個生命週期的例項:

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IOperationTransient, Operation>();
    services.AddScoped<IOperationScoped, Operation>();
    services.AddSingleton<IOperationSingleton, Operation>();
    services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
    // OperationService depends on each of the other Operation types.
    services.AddTransient<OperationService, OperationService>();
}

再在IndexModel模組裡面呼叫OnGet方法輸出,觀察IOperation與OperationService類屬性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 void OnGet()
    {
        Console.WriteLine("IOperation操作:");
        Console.WriteLine("暫時:" + _transientOperation.OperationId.ToString());
        Console.WriteLine("作用域:" + _scopedOperation.OperationId.ToString());
        Console.WriteLine("單例:" + _singletonOperation.OperationId.ToString());
        Console.WriteLine("例項:" + _singletonInstanceOperation.OperationId.ToString());
        Console.WriteLine("OperationService操作:");
        Console.WriteLine("暫時:" + _operationService._transientOperation.OperationId.ToString());
        Console.WriteLine("作用域:" + _operationService._scopedOperation.OperationId.ToString());
        Console.WriteLine("單例:" + _operationService._singletonOperation.OperationId.ToString());
        Console.WriteLine("例項:" + _operationService._singletonInstanceOperation.OperationId.ToString());
    }
}

執行IndexModel 類輸出結果:

由圖總結如下:
2.1 Transient(暫時):每次呼叫服務的時候都會建立一個新的例項。即在IndexModel類的區域性方法或屬性中(這裡是OnGet方法)例項化一個依賴物件Operation類,虛擬碼是:

public class IndexModel: PageModel
{
    public void OnGet()
    {
          //呼叫IndexModel類時,例項化了兩次Operation類
      //第一次
          OperationService operationService=new OperationService();
     //第二次
     IOperationTransient TransientOperation=new Operation();
    }
}

2.2 Scoped(作用域):一次請求(Action)內物件例項是相同的,但每次請求會產生一個新例項。相當於在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
}

2.3 Singleton(單例):首次請求初始化同一個例項,後續每次請求都使用同一個例項。相當於在整個應用Application中只例項化一次例項,常見的單例模式。

參考文獻:
在ASP.NET Core依賴