如何解決 ASP.NET Core 中的依賴問題

語言: CN / TW / HK

依賴性注入是一種技術,它允許我們注入一個特定類的依賴物件,而不是直接建立這些例項。

使用依賴注入的好處顯而易見,它通過放鬆模組間的耦合,來增強系統的可維護性和可測試性。

依賴注入允許我們修改具體實現,而不必改變依賴於它們的依賴型別。

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#教程​