如何解決 ASP.NET Core 中的依賴問題
依賴性注入是一種技術,它允許我們注入一個特定類的依賴對象,而不是直接創建這些實例。
使用依賴注入的好處顯而易見,它通過放鬆模組間的耦合,來增強系統的可維護性和可測試性。
依賴注入允許我們修改具體實現,而不必改變依賴於它們的依賴類型。
ASP.NET Core 很重視依賴注入技術。ASP.NET Core 中內置的依賴注入提供功能模組,並不像 StructureMap 和 Ninject 等IoC(控制反轉)容器那樣功能豐富,但它速度快,易於配置,而且易於使用。我們可以使用它在 ASP.NET Core 中注入框架服務和應用程式服務。
關於依賴注入和控制反轉的有關知識可以參考:設計模式。
我們將介紹三種不同方法來解決 ASP.NET Core 6 中的依賴項。
本文中提供的程式碼示例均默認運行在 Visual Studio 2022。
1. 使用 VS2022 創建 ASP.NET Core 項目
我們在 Visual Studio 2022 中創建一個 ASP.NET Core 項目。按照以下步驟在 Visual Studio 2022 中創建一個新的 ASP.NET Core Web API 6 項目。
- 1) 啟動 Visual Studio 2022 IDE。
- 2) 單擊 「Create new project」。
- 3) 在 「Create new project」 窗口中,從顯示的模板列表中選擇 「ASP.NET Core Web API」。
- 4) 點擊下一步。
- 5) 在 「Configure your new project」 窗口中,指定新項目的名稱和位置。
- 6) 根據您的偏好,可選擇選中 「Place solution and project in the same directory」 複選框。
- 7) 點擊下一步。
- 8) 在接下來顯示的 「Additional Information」 窗口中,從頂部的下拉列表中選擇 .NET 6.0 作為目標框架。將 「Authentication Type」 保留為 「None」(默認)。
- 9) 確保未選中 「Enable Docker,」、「Configure for HTTPS」 和 「Enable Open API Support」 複選框,因為我們不會在此處使用任何這些功能。您也可以選擇取消選中 「Use controllers(取消選中以使用最少的 API)」 複選框,因為我們將創建自己的控制器。
- 10) 單擊創建。
這將在 Visual Studio 2022 中創建一個新的 ASP.NET Core 6 Web API 項目。我們將在本文的後續部分中使用該項目來說明解析依賴項。
2. 使用構造函數注入解決依賴關係
現在創建以下介面:
public interface ICustomFileLogger { public string Text { get; set; } public void Log(string message); }
為簡單起見,我們給出一個最小的表示。
CustomFileLogger 類實現 ICustomFileLogger 介面,程式碼如下:
public class CustomFileLogger : ICustomFileLogger { public string Text { get; set; } public void Log(string message) { // 自己的實現邏輯 } }
如果使用的是 ASP.NET 5,可以在 ConfigureServices 方法中註冊一個 ICustomFileLogger 類型的實例作為一個 Scoped 服務。如果使用的是 ASP.NET 6,則直接在 Program.cs 文件中註冊。
services.AddScoped<ICustomFileLogger, CustomFileLogger>();
接下來,創建一個名為 DefaultController 的 API 控制器並輸入以下程式碼:
[Route("api/[controller]")] [ApiController] public class DefaultController : ControllerBase { private ICustomFileLogger _logger; public DefaultController(ICustomFileLogger logger) { _logger = logger; if(string.IsNullOrEmpty(_logger.Text)) _logger.Text = DateTime.UtcNow.ToString(); } [HttpGet] public string Get() { return "Hello World!"; } }
注意這裡是如何使用構造函數注入的。DefaultController 類的構造函數接受 ICustomFileLogger 類型的實例作為參數。
3. 使用動作方法注入解決依賴關係
當需要在多個方法中使用注入的實例時,我們應該使用構造函數注入。如果只需要在特定的動作方法中使用實例,最好在動作方法中注入實例,而不是使用構造函數注入。
以下程式碼片段說明了如何實現動作方法注入。
[HttpPost("Log")] public IActionResult Log([FromServices] ICustomFileLogger customFileLogger) { // 自己的實現邏輯 return Ok(); }
4. 使用 IServiceProvider 解決依賴關係
我們有時候可能經常需要在控制器中注入許多不同的服務。如果使用構造函數注入,則必須在構造函數中指定多個參數。所以,這種場景下,有一個更好的解決方案,就是使用 IServiceProvider。
我們可以使用 IServiceCollection 介面來創建依賴項注入容器。一旦創建了容器,IServiceCollection 實例就會組合成一個 IServiceProvider 實例。我們可以使用此實例來解析服務。
我們可以將 IServiceProvider 類型的實例注入到類的任何方法中。您還可以利用 IApplicationBuilder 介面的 ApplicationServices 屬性和 HttpContext 類的 RequestServices 屬性來檢索 IServiceProvider 實例。
以下程式碼說明了如何注入 IServiceProvider 類型的實例:
public class DefaultController : Controller { private IServiceProvider _provider; public DefaultController(IServiceProvider provider) { _provider = provider; } }
我們可以在操作方法中使用以下程式碼,來檢索需要的任何服務實例。
ICustomFileLogger logger = (ICustomFileLogger)_provider.GetService(typeof(ICustomFileLogger));
注意 IServiceProvider 的 GetService 方法是如何用來檢索服務實例的。
我們可以使用 HttpContext 類的 RequestServices 屬性來檢索 IServiceProvider 類型的實例,然後使用該實例調用 GetService 方法。
以下程式碼展示了HttpContext 類如何做到檢索實例:
ICustomFileLogger logger = (ICustomFileLogger)HttpContext.RequestServices.GetService(typeof(ICustomFileLogger));
5. 總結
依賴性注入是一種通過放鬆耦合來增強程式碼維護和可測試性的方法。
我們可以使用 ASP.NET Core 中內置的依賴注入支援來創建模組化、精簡和乾淨的應用程式,同時也使應用程式更容易維護和測試。
參考資料:
1. 設計模式
2. C#教程