Dela via


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äses med Azure Functions på konsumtionsplanen.

  • 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 process med körningstiden. 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 ett loggningsverktyg som registreras vid uppstart. 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ärdtjänsten konfigurerar ASP.NET-autentiseringstjänster för att korrekt exponera API:er för grundläggande livscykeloperationer. Andra konfigurationer i en anpassad Startup klass kan åsidosätta den här konfigurationen, vilket orsakar oavsiktliga konsekvenser. Till exempel kan anrop av builder.Services.AddAuthentication() avbryta autentiseringen mellan portalen och värden, vilket kan leda till 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 injiceras 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-program tillhandahåller samma tjänstelivslängder som ASP.NET Dependency Injection. 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.
  • Kapslad: Den kapslade servicelivslängden motsvarar en funktionsutförandets livslängd. Tjänster med avgränsat omfång 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 loggningsleverantör registrerar du en anpassad typ som ett exemplar av ILoggerProvider, vilket är tillgängligt 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, skapa en via den infogade TelemetryConfiguration som visas i Logga anpassad telemetri i C#-funktioner.

ILogger<T> och ILoggerFactory

Värden injicerar 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 funktionella appar

Funktionens värd registrerar många olika tjänster och servicefunktioner. 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.

Överordnande 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 som läses in i konfigurationsinstansen måste vara enkla nyckel-/värdepar. 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 vars namn stämmer överens 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);
    });

Anropa Bind kopierar konfigurationens värden med matchande egenskapsnamn 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 appen 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 lagras i versionshanteringen. 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 egenskapen ConfigurationBuilder av 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: