依賴注入這個主題大概就可以寫五天了吧(?),這個系列就不多作介紹了,詳細的可以參考英文微基,網路上也有很多相關文章 (其實是自己講不清楚)。今天會針對如何在 ASP.NET Core 中使用依賴注入作介紹。
開始註冊服務之前,我們先來了解服務的生命周期。註冊服務時需設定生命周期,有三種生命周期設定:
Startup.ConfigureSerivces
中註冊時提供新的實例。之後每次被注入時都會使用同一個實例。如果應用程式中需要 Singleton 行為,建議讓服務容器來管理其生命周期,不要自己實作。看這麼多字,不如用範例來比較一下不同生命周期的差異吧!我們以唯一識別碼「OperationId
」來代表不同的工作,並觀察使用不同生命周期註冊服務時的差異。參考完整原始碼
首先建立不同介面代表不同生命周期設定的類型:
public interface IOperation
{
Guid OperationId { get; }
}
public interface IOperationTransient : IOperation
{
}
public interface IOperationScoped : IOperation
{
}
public interface IOperationSingleton : IOperation
{
}
public interface IOperationSingletonInstance : IOperation
{
}
建立 Operation
類別來實作這些介面。建構元會傳入一個 GUID,如果沒有傳入則會建立一個新的 GUID:
public class Operation :
IOperationTransient,
IOperationScoped,
IOperationSingleton,
IOperationSingletonInstance
{
public Operation() : this(Guid.NewGuid())
{
}
public Operation(Guid id)
{
OperationId = id;
}
public Guid OperationId { get; }
}
新增一個相依四種 Operation
類型的 OperationService
類別:
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));
services.AddTransient<OperationService, OperationService>();
}
新增一個 DependencyInjectionLifetimesController
控制器類別,注入上面建立的這些服務,並新增一個 Index
Action,把被注入的服務都加到 ViewBag
中以在 View 中使用。
public class DependencyInjectionLifetimesController : Controller
{
private readonly IOperationTransient _transientOperation;
private readonly IOperationScoped _scopedOperation;
private readonly IOperationSingleton _singletonOperation;
private readonly IOperationSingletonInstance _singletonInstanceOperation;
private readonly OperationService _operationService;
public DependencyInjectionLifetimesController(IOperationTransient transientOperation, IOperationScoped scopedOperation, IOperationSingleton singletonOperation, IOperationSingletonInstance singletonInstanceOperation, OperationService operationService)
{
_transientOperation = transientOperation;
_scopedOperation = scopedOperation;
_singletonOperation = singletonOperation;
_singletonInstanceOperation = singletonInstanceOperation;
_operationService = operationService;
}
// GET: /<controller>/
public IActionResult Index()
{
ViewBag.Transient = _transientOperation;
ViewBag.Scoped = _scopedOperation;
ViewBag.Singleton = _singletonOperation;
ViewBag.SingletonInstance = _singletonInstanceOperation;
ViewBag.Service = _operationService;
return View();
}
}
最後,建立 DependencyInjectionLifetimes/Index.cshtml
,對應到 Controller/Action 的 View:
@{
ViewData["Title"] = "Dependency Injection Lifetimes Example";
}
<style>
table tr td {
padding: 5px;
}
table tr td:first-child {
text-align: right;
font-weight: bold;
}
</style>
<h2>生命周期範例</h2>
<hr />
<h3>Controller Operations</h3>
<table>
<tr>
<td>Transient</td>
<td>@ViewBag.Transient.OperationId</td>
</tr>
<tr>
<td>Scoped</td>
<td>@ViewBag.Scoped.OperationId</td>
</tr>
<tr>
<td>Singleton</td>
<td>@ViewBag.Singleton.OperationId</td>
</tr>
<tr>
<td>SingletonInstance</td>
<td>@ViewBag.SingletonInstance.OperationId</td>
</tr>
</table>
<hr />
<h3>OperationService Operations</h3>
<table>
<tr>
<td>Transient</td>
<td>@ViewBag.Service.TransientOperation.OperationId</td>
</tr>
<tr>
<td>Scoped</td>
<td>@ViewBag.Service.ScopedOperation.OperationId</td>
</tr>
<tr>
<td>Singleton</td>
<td>@ViewBag.Service.SingletonOperation.OperationId</td>
</tr>
<tr>
<td>SingletonInstance</td>
<td>@ViewBag.Service.SingletonInstanceOperation.OperationId</td>
</tr>
</table>
執行應用程式後,用瀏覽器開兩個分頁觀察 OperationId 在兩次請求的差異: