在 .NET Azure Functions 中使用相依性插入

Azure Functions 支援相依性插入 (DI) 軟體設計模式,這是在類別及其相依性之間達成控制反轉 (IoC) 的技術。

  • Azure Functions 中的相依性插入是以 .NET Core 相依性插入功能為基礎。 建議熟悉 .NET Core 相依性插入 (機器翻譯)。 您覆寫相依性的方式,與在取用方案上使用 Azure Functions 讀取設定值的方式有所不同。

  • 從 Azure Functions 2.x 開始支援相依性插入。

  • 相依性插入模式取決於您的 C# 函式是在同處理序跨處理序執行。

重要

本文中的指引僅適用於與執行階段在同處理序執行的 C# 類別庫函式。 此自訂相依性插入模型不適用於 .NET 隔離的函式,這可讓您在跨處理序執行 .NET 函式。 .NET 隔離背景工作處理序模型依賴一般 ASP.NET Core 相依性插入模式。 若要深入了解,請參閱 .NET 隔離背景工作處理序指南中的相依性插入

必要條件

您必須安裝下列 NuGet 套件,才能使用相依性插入:

註冊伺服器

若要註冊服務,請建立方法來設定元件並將其新增至 IFunctionsHostBuilder 執行個體。 Azure Functions 主機會建立 IFunctionsHostBuilder 的執行個體,並將其直接傳入方法。

警告

針對在取用或進階方案中執行的函數應用程式,修改觸發程序中所使用的設定值可能會導致調整錯誤。 類別 FunctionsStartup 對這些屬性所做的任何變更都會導致函數應用程式啟動錯誤。

插入 IConfiguration 可能會導致非預期的行為。 若要深入了解如何新增設定來源,請參閱自訂設定來源 (部分機器翻譯)。

若要註冊方法,請新增 FunctionsStartup 組件屬性,以指定啟動期間所使用的類型名稱。

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]

namespace MyNamespace;

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddHttpClient();

        builder.Services.AddSingleton<IMyService>((s) => {
            return new MyService();
        });

        builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();
    }
}

此範例會使用在啟動時註冊 HttpClient 所需的 Microsoft.Extensions.Http 套件。

警示

在執行階段處理啟動類別的前後會執行一系列註冊步驟。 因此,請記住下列項目:

  • 啟動類別僅適用於設定和註冊。 避免使用啟動時在啟動程序期間註冊的服務。 例如,請勿嘗試在啟動期間註冊的記錄器中記錄訊息。 註冊程序的這個時間點太早,還無法提供服務使用。 執行 Configure 方法之後,Functions 執行階段會繼續註冊其他相依性,這可能會影響服務的運作方式。

  • 相依性插入容器只會保留明確註冊的類型。 唯一做為可插入類型使用的服務是設定在 Configure 方法中的服務。 因此,Function 特定類型 (例如 BindingContextExecutionContext) 無法在設定期間使用或作為可插入的類型使用。

  • 不支援設定 ASP.NET 驗證。 Functions 主機會設定 ASP.NET 驗證服務,以正確地公開核心生命週期作業的 API。 在自訂 Startup 類別中的其他設定可能會覆寫此設定,導致非預期的結果。 例如,呼叫 builder.Services.AddAuthentication() 可能會中斷入口網站與主機之間的驗證,導致出現「無法連線到 Azure Functions 執行階段」之類的訊息。

使用插入的相依性

您可使用建構函式插入,讓相依性可供函式使用。 使用建構函式插入時,您不得將靜態類別用於插入服務或函式類別。

下列範例示範如何將 IMyServiceHttpClient 相依性插入 HTTP 觸發的函式中。

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using System.Net.Http;
using System.Threading.Tasks;

namespace MyNamespace;

public class MyHttpTrigger
{
    private readonly HttpClient _client;
    private readonly IMyService _service;

    public MyHttpTrigger(IHttpClientFactory httpClientFactory, IMyService service)
    {
        this._client = httpClientFactory.CreateClient();
        this._service = service;
    }

    [FunctionName("MyHttpTrigger")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
    {
        var response = await _client.GetAsync("https://microsoft.com");
        var message = _service.GetMessage();

        return new OkObjectResult("Response from function with injected dependencies.");
    }
}

此範例會使用在啟動時註冊 HttpClient 所需的 Microsoft.Extensions.Http 套件。

執行個體存留期

Azure Functions 應用程式提供與 ASP.NET 相依性插入相同的服務存留期。 針對 Functions 應用程式,不同服務存留期的行為如下所示:

  • 暫時性:暫時性服務會在每次服務解析時建立。
  • 有限範圍:有限範圍的服務存留期符合函式執行存留期。 限域服務會在每次執行函式後建立。 稍後在執行期間對該服務提出的要求會重複使用現有服務執行個體。
  • singleton:singleton 服務存留期符合主機存留期,而且在該執行個體上跨函式執行重複使用。 建議連線和用戶端使用單一存留期服務,例如 DocumentClientHttpClient 執行個體。

請前往 GitHub 檢視或下載不同服務存留期的範本

記錄服務

如果您需要自己的記錄提供者,請將自訂類型註冊為 ILoggerProvider 的執行個體,可透過 Microsoft.Extensions.Logging.Abstractions NuGet 套件取得。

Azure Functions 會自動新增 Application Insights。

警告

  • 請勿將 AddApplicationInsightsTelemetry() 新增至服務集合,因為這會註冊與環境所提供服務衝突的服務。
  • 若您使用的是內建 Application Insights 功能,請勿註冊自己的 TelemetryConfigurationTelemetryClient。 如果需要設定自己的 TelemetryClient 執行個體,請透過插入的 TelemetryConfiguration 建立一個,如 C# 函式中記錄自訂遙測資料中所示。

ILogger<T> 和 ILoggerFactory

主機會將 ILogger<T>ILoggerFactory 服務插入建構函式中。 不過,預設會從函式記錄篩選掉這些新的記錄篩選。 您必須修改 host.json 檔案,以選擇加入額外的篩選和類別。

下列範例示範如何新增 ILogger<HttpTrigger> 以及已向主機公開的記錄。

namespace MyNamespace;

public class HttpTrigger
{
    private readonly ILogger<HttpTrigger> _log;

    public HttpTrigger(ILogger<HttpTrigger> log)
    {
        _log = log;
    }

    [FunctionName("HttpTrigger")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req)
    {
        _log.LogInformation("C# HTTP trigger function processed a request.");

        // ...
}

下列範例 host.json 檔案會新增記錄篩選條件。

{
    "version": "2.0",
    "logging": {
        "applicationInsights": {
            "samplingSettings": {
                "isEnabled": true,
                "excludedTypes": "Request"
            }
        },
        "logLevel": {
            "MyNamespace.HttpTrigger": "Information"
        }
    }
}

如需記錄層級的詳細資訊,請參閱設定記錄層級

函數應用程式提供的服務

函式主機會註冊許多服務。 下列服務可安全地作為應用程式中的相依性:

服務類型 存留期 描述
Microsoft.Extensions.Configuration.IConfiguration 單一 執行階段設定
Microsoft.Azure.WebJobs.Host.Executors.IHostIdProvider 單一 負責提供主機執行個體的識別碼

如有其他要相依的服務,請在 GitHub 上建立並張貼問題

覆寫主機服務

目前不支援覆寫主機所提供的服務。 如有要覆寫的服務,請在 GitHub 上建立並張貼問題

使用選項和設定

應用程式設定中定義的值位於 IConfiguration 執行個體中,其可供讀取啟動類別中的應用程式設定值。

您可將值從 IConfiguration 執行個體擷取到自訂類型中。 將應用程式設定值複製到自訂類型會使這些值得以插入,以供輕鬆地測試服務。 讀入設定執行個體的設定必須是簡單的索引鍵/值組。 針對在彈性進階方案中執行的函式,應用程式設定名稱只能包含字母、數字 (0-9)、句號 (.)、冒號 (:) 和底線 (_)。 如需詳細資訊,請參閱應用程式設定考量 (部分機器翻譯)。

請考慮下列類別,其中包含名稱與應用程式設定一致的屬性:

public class MyOptions
{
    public string MyCustomSetting { get; set; }
}

local.settings.json 檔案可能會建構自訂設定,如下所示:

{
  "IsEncrypted": false,
  "Values": {
    "MyOptions:MyCustomSetting": "Foobar"
  }
}

您可從 Startup.Configure 方法內部使用下列程式碼,以將值從 IConfiguration 執行個體擷取到自訂類型中:

builder.Services.AddOptions<MyOptions>()
    .Configure<IConfiguration>((settings, configuration) =>
    {
        configuration.GetSection("MyOptions").Bind(settings);
    });

呼叫 Bind 會將具有相符屬性名稱的值從設定複製到自訂執行個體中。 選項執行個體現在可供 IoC 容器用來插入函式中。

選項物件會作為一般 IOptions 介面的執行個體插入函式中。 您可使用 Value 屬性來存取在設定中找到的值。

using System;
using Microsoft.Extensions.Options;

public class HttpTrigger
{
    private readonly MyOptions _settings;

    public HttpTrigger(IOptions<MyOptions> options)
    {
        _settings = options.Value;
    }
}

如需詳細資訊,請參閱 ASP.NET Core 中的選項模式

使用 ASP.NET Core 使用者祕密

當您在本機開發應用程式時,ASP.NET Core 會提供祕密管理員工具,讓您可以將祕密資訊儲存在專案根目錄之外。 此工具降低了祕密被意外提交至原始檔控制的可能性。 Azure Functions Core Tools (3.0.3233 版或更新版本) 會自動讀取 ASP.NET Core 祕密管理員所建立的祕密。

若要將 .NET Azure Functions 專案設定為使用使用者祕密,請在專案根目錄中執行下列命令。

dotnet user-secrets init

然後使用 dotnet user-secrets set 命令來建立或更新祕密。

dotnet user-secrets set MySecret "my secret value"

若要存取函數應用程式程式碼中的使用者祕密值,請使用 IConfigurationIOptions

自訂設定來源

若要指定其他設定來源,請覆寫函式應用程式 StartUp 類別中的 ConfigureAppConfiguration 方法。

下列範例從基本與選擇性環境特定應用程式設定檔中新增設定值。

using System.IO;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]

namespace MyNamespace;

public class Startup : FunctionsStartup
{
    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
        FunctionsHostBuilderContext context = builder.GetContext();

        builder.ConfigurationBuilder
            .AddJsonFile(Path.Combine(context.ApplicationRootPath, "appsettings.json"), optional: true, reloadOnChange: false)
            .AddJsonFile(Path.Combine(context.ApplicationRootPath, $"appsettings.{context.EnvironmentName}.json"), optional: true, reloadOnChange: false)
            .AddEnvironmentVariables();
    }
    
    public override void Configure(IFunctionsHostBuilder builder)
    {
    }
}

將設定提供者新增至 IFunctionsConfigurationBuilderConfigurationBuilder 屬性。 如需使用設定提供者的詳細資訊,請參閱 ASP.NET Core 中的設定

FunctionsHostBuilderContext 是自 IFunctionsConfigurationBuilder.GetContext() 取得。 使用此內容來擷取目前的環境名稱,並解析函數應用程式資料夾中設定檔的位置。

根據預設,appsettings.json 等設定檔不會自動複製到函數應用程式的輸出檔案夾。 更新 .csproj 檔案以符合下列範例,以確保檔案已複製。

<None Update="appsettings.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>      
</None>
<None Update="appsettings.Development.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>

下一步

如需詳細資訊,請參閱以下資源: