在 ASP.NET Core 開發中,DI (dependency injection) 是最核心的設計模式之一,AddTransient(), AddScoped(), AddSingleton() 三種生命週期的差異能達到的目標截然不同,本文希望釐清當中的目的以及誤解。
核心概念
三種生命週期的定義
| 生命週期 |
實例建立時機 |
使用場景 |
| Transient |
每次注入時都建立新實例 |
輕量級、無狀態的服務 |
| Scoped |
每個 HTTP Request 內共用同一實例 |
DbContext、需要在單一請求內保持狀態的服務 |
| Singleton |
整個應用程式生命週期只建立一次 |
設定檔、快取、共用資源 |
常見誤解
Scoped 以及 Transient 常會被人誤解
Scoped:每一次的 Request 是共用同一個 Service Instance
Transient:每一次的 Request,每次使用 Service 都會建立一個的 Instance
範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
|
public interface IExampleService { Guid InstanceId { get; } }
public class ExampleService : IExampleService { public Guid InstanceId { get; } = Guid.NewGuid(); public ExampleService() { Console.WriteLine($"ExampleService 建立: {InstanceId}"); } }
[ApiController] [Route("api/[controller]")] public class LifecycleController : ControllerBase { private readonly IExampleService _service1; private readonly IExampleService _service2;
public LifecycleController( IExampleService service1, IExampleService service2) { _service1 = service1; _service2 = service2; }
[HttpGet("test")] public IActionResult Test( [FromServices] IExampleService service3) { return Ok(new { Service1 = _service1.InstanceId, Service2 = _service2.InstanceId, Service3 = service3.InstanceId, AllSame = _service1.InstanceId == _service2.InstanceId && _service2.InstanceId == service3.InstanceId }); } }
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(); var app = builder.Build(); app.MapControllers(); app.Run();
builder.Services.AddTransient<IExampleService, ExampleService>();
builder.Services.AddScope<IExampleService, ExampleService>();
|