Använda beroendeinmatning i .NET Azure Functions

Azure Functions stöder designmönstret för beroendeinmatning (DI), vilket är en teknik för att uppnå inversion av kontroll (IoC) mellan klasser och deras beroenden.

  • Beroendeinmatning i Azure Functions bygger på .NET Core Dependency Injection-funktionerna. Förtrogenhet med .NET Core-beroendeinmatning rekommenderas. Det finns skillnader i hur du åsidosätter beroenden och hur konfigurationsvärden läse med Azure Functions i förbrukningsplanen.

  • Stöd för beroendeinmatning börjar med Azure Functions 2.x.

  • Beroendeinmatningsmönster varierar beroende på om C#-funktionerna körs i processen eller inte.

Viktigt!

Vägledningen i den här artikeln gäller endast för C#-klassbiblioteksfunktioner som körs i processen med körningen. Den här anpassade beroendeinmatningsmodellen gäller inte för .NET-isolerade funktioner, vilket gör att du kan köra .NET-funktioner utan process. Den isolerade .NET-arbetsprocessmodellen förlitar sig på vanliga ASP.NET Core-beroendeinmatningsmönster. Mer information finns i Beroendeinmatning i processguiden för isolerad .NET-arbetsprocess.

Förutsättningar

Innan du kan använda beroendeinmatning måste du installera följande NuGet-paket:

Registrera tjänster

Om du vill registrera tjänster skapar du en metod för att konfigurera och lägga till komponenter i en IFunctionsHostBuilder instans. Azure Functions-värden skapar en instans av IFunctionsHostBuilder och skickar den direkt till din metod.

Varning

För funktionsappar som körs i förbruknings- eller Premium-abonnemangen kan ändringar av konfigurationsvärden som används i utlösare orsaka skalningsfel. Eventuella ändringar av dessa egenskaper av FunctionsStartup klassen resulterar i ett startfel för funktionsappen.

Inmatning av IConfiguration kan leda till oväntat beteende. Mer information om hur du lägger till konfigurationskällor finns i Anpassa konfigurationskällor.

Om du vill registrera metoden lägger du till sammansättningsattributet FunctionsStartup som anger typnamnet som användes vid start.

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>();
    }
}

I det här exemplet används det Microsoft.Extensions.Http-paket som krävs för att registrera en HttpClient vid start.

Varningar

En serie registreringssteg körs före och efter körningen bearbetar startklassen. Tänk därför på följande:

  • Startklassen är endast avsedd för installation och registrering. Undvik att använda tjänster som registrerats vid start under startprocessen. Försök till exempel inte logga ett meddelande i en loggning som registreras under starten. Den här punkten i registreringsprocessen är för tidig för att dina tjänster ska vara tillgängliga för användning. Configure När metoden har körts fortsätter Functions-körningen att registrera andra beroenden, vilket kan påverka hur dina tjänster fungerar.

  • Containern för beroendeinmatning innehåller endast explicit registrerade typer. De enda tjänster som är tillgängliga som injicerbara typer är de som konfigureras i Configure metoden. Det innebär att funktionsspecifika typer som BindingContext och ExecutionContext inte är tillgängliga under installationen eller som injicerbara typer.

  • Det går inte att konfigurera ASP.NET autentisering. Functions-värden konfigurerar ASP.NET autentiseringstjänster så att API:er exponeras korrekt för kärnlivscykelåtgärder. Andra konfigurationer i en anpassad Startup klass kan åsidosätta den här konfigurationen, vilket orsakar oavsiktliga konsekvenser. Anrop builder.Services.AddAuthentication() kan till exempel avbryta autentiseringen mellan portalen och värden, vilket leder till att meddelanden som Azure Functions-körning inte kan nås.

Använda inmatade beroenden

Konstruktorinmatning används för att göra dina beroenden tillgängliga i en funktion. Användning av konstruktorinmatning kräver att du inte använder statiska klasser för inmatade tjänster eller för dina funktionsklasser.

Följande exempel visar hur beroendena IMyService och HttpClient matas in i en HTTP-utlöst funktion.

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.");
    }
}

I det här exemplet används det Microsoft.Extensions.Http-paket som krävs för att registrera en HttpClient vid start.

Tjänstlivslängd

Azure Functions-appar ger samma tjänstlivslängd som ASP.NET beroendeinmatning. För en Functions-app fungerar de olika tjänstlivslängderna på följande sätt:

  • Tillfälligt: Tillfälliga tjänster skapas vid varje lösning av tjänsten.
  • Omfattning: Den begränsade tjänstlivslängden matchar en livslängd för funktionskörning. Begränsade tjänster skapas en gång per funktionskörning. Senare begäranden för tjänsten under körningen återanvänder den befintliga tjänstinstansen.
  • Singleton: Livslängden för singleton-tjänsten matchar värdlivslängden och återanvänds över funktionskörningar på den instansen. Singleton-livslängdstjänster rekommenderas för anslutningar och klienter, till exempel DocumentClient eller HttpClient instanser.

Visa eller ladda ned ett exempel på olika tjänstlivslängder på GitHub.

Loggningstjänster

Om du behöver en egen loggningsprovider registrerar du en anpassad typ som en instans av ILoggerProvider, som är tillgänglig via NuGet-paketet Microsoft.Extensions.Logging.Abstractions .

Application Insights läggs till automatiskt av Azure Functions.

Varning

  • Lägg inte till AddApplicationInsightsTelemetry() i tjänstesamlingen, som registrerar tjänster som är i konflikt med tjänster som tillhandahålls av miljön.
  • Registrera inte dina egna TelemetryConfiguration eller TelemetryClient om du använder den inbyggda Application Insights-funktionen. Om du behöver konfigurera din egen TelemetryClient instans skapar du en via den inmatade TelemetryConfiguration som visas i Logga anpassad telemetri i C#-funktioner.

ILogger<T> och ILoggerFactory

Värden matar in ILogger<T> och ILoggerFactory tjänster i konstruktorer. Dessa nya loggningsfilter filtreras dock som standard bort från funktionsloggarna. Du måste ändra host.json filen för att välja extra filter och kategorier.

I följande exempel visas hur du lägger till en ILogger<HttpTrigger> med loggar som exponeras för värden.

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.");

        // ...
}

Följande exempelfil host.json lägger till loggfiltret.

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

Mer information om loggnivåer finns i Konfigurera loggnivåer.

Tjänster som tillhandahålls av funktionsappar

Funktionsvärden registrerar många tjänster. Följande tjänster är säkra att ta som ett beroende i ditt program:

Tjänsttyp Livstid beskrivning
Microsoft.Extensions.Configuration.IConfiguration Singleton Körningskonfiguration
Microsoft.Azure.WebJobs.Host.Executors.IHostIdProvider Singleton Ansvarig för att tillhandahålla ID för värdinstansen

Om det finns andra tjänster som du vill vara beroende av skapar du ett problem och föreslår dem på GitHub.

Åsidosättande värdtjänster

Övergripande tjänster som tillhandahålls av värden stöds för närvarande inte. Om det finns tjänster som du vill åsidosätta skapar du ett problem och föreslår dem på GitHub.

Arbeta med alternativ och inställningar

Värden som definierats i appinställningar är tillgängliga i en IConfiguration instans, vilket gör att du kan läsa appinställningars värden i startklassen.

Du kan extrahera värden från instansen IConfiguration till en anpassad typ. Om du kopierar appinställningarnas värden till en anpassad typ kan du enkelt testa dina tjänster genom att göra dessa värden injicerbara. Inställningar läsa in konfigurationsinstansen måste vara enkla nyckel/värde-par. För funktioner som körs i en Elastic Premium-plan kan namn på programinställningar endast innehålla bokstäver, siffror (0-9), punkter (.), kolon (:) och understreck (_). Mer information finns i Överväganden för appinställningar.

Tänk på följande klass som innehåller en egenskap som heter konsekvent med en appinställning:

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

Och en local.settings.json fil som kan strukturera den anpassade inställningen enligt följande:

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

Inifrån Startup.Configure metoden kan du extrahera värden från instansen IConfiguration till din anpassade typ med hjälp av följande kod:

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

Anropar Bind kopior som har matchande egenskapsnamn från konfigurationen till den anpassade instansen. Alternativinstansen är nu tillgänglig i IoC-containern för att mata in i en funktion.

Alternativobjektet matas in i funktionen som en instans av det allmänna IOptions gränssnittet. Använd egenskapen Value för att komma åt de värden som finns i konfigurationen.

using System;
using Microsoft.Extensions.Options;

public class HttpTrigger
{
    private readonly MyOptions _settings;

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

Mer information finns i Alternativmönster i ASP.NET Core.

Använda ASP.NET Core-användarhemligheter

När du utvecklar din app lokalt tillhandahåller ASP.NET Core ett Secret Manager-verktyg som gör att du kan lagra hemlig information utanför projektroten. Det gör det mindre troligt att hemligheter oavsiktligt checkas in till källkontrollen. Azure Functions Core Tools (version 3.0.3233 eller senare) läser automatiskt hemligheter som skapats av ASP.NET Core Secret Manager.

Kör följande kommando i projektroten för att konfigurera ett .NET Azure Functions-projekt att använda användarhemligheter.

dotnet user-secrets init

Använd dotnet user-secrets set sedan kommandot för att skapa eller uppdatera hemligheter.

dotnet user-secrets set MySecret "my secret value"

Om du vill komma åt värden för användarhemligheter i funktionsappens kod använder du IConfiguration eller IOptions.

Anpassa konfigurationskällor

Om du vill ange andra konfigurationskällor åsidosätter du ConfigureAppConfiguration metoden i funktionsappens StartUp klass.

Följande exempel lägger till konfigurationsvärden från både grundläggande och valfria miljöspecifika appinställningarsfiler.

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)
    {
    }
}

Lägg till konfigurationsprovidrar i ConfigurationBuilder egenskapen IFunctionsConfigurationBuilder. Mer information om hur du använder konfigurationsprovidrar finns i Konfiguration i ASP.NET Core.

A FunctionsHostBuilderContext hämtas från IFunctionsConfigurationBuilder.GetContext(). Använd den här kontexten för att hämta det aktuella miljönamnet och matcha platsen för konfigurationsfilerna i funktionsappmappen.

Som standard kopieras inte konfigurationsfiler som appsettings.json automatiskt till funktionsappens utdatamapp. .csproj Uppdatera filen så att den matchar följande exempel för att se till att filerna kopieras.

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

Nästa steg

Mer information finns i följande resurser: