Afhankelijkheidsinjectie gebruiken in .NET Azure Functions

Azure Functions ondersteunt het ontwerppatroon voor afhankelijkheidsinjectie (DI). Dit is een techniek om Inversion of Control (IoC) tussen klassen en hun afhankelijkheden te bereiken.

  • Afhankelijkheidsinjectie in Azure Functions is gebaseerd op de functies voor .NET Core-afhankelijkheidsinjectie. Kennis van .NET Core-afhankelijkheidsinjectie wordt aanbevolen. Er zijn verschillen in de manier waarop u afhankelijkheden overschrijven en hoe configuratiewaarden worden gelezen met Azure Functions in het verbruiksplan.

  • Ondersteuning voor afhankelijkheidsinjectie begint met Azure Functions 2.x.

  • Patronen voor afhankelijkheidsinjectie zijn afhankelijk van of uw C#-functies worden uitgevoerd in-process of out-of-process.

Belangrijk

De richtlijnen in dit artikel zijn alleen van toepassing op C#-klassebibliotheekfuncties, die tijdens de runtime worden uitgevoerd. Dit aangepaste afhankelijkheidsinjectiemodel is niet van toepassing op geïsoleerde .NET-functies,waarmee u .NET 5.0-functies buiten het proces kunt uitvoeren. Het geïsoleerde .NET-procesmodel is afhankelijk van ASP.NET Core patronen voor afhankelijkheidsinjectie. Zie Afhankelijkheidsinjectie in de proceshandleiding voor geïsoleerde .NET-gegevens voor meer informatie.

Vereisten

Voordat u afhankelijkheidsinjectie kunt gebruiken, moet u de volgende NuGet-pakketten installeren:

Services registreren

Als u services wilt registreren, maakt u een methode om onderdelen te configureren en toe te voegen aan een IFunctionsHostBuilder exemplaar. De Azure Functions host maakt een exemplaar van IFunctionsHostBuilder en geeft deze rechtstreeks door aan uw methode.

Als u de methode wilt registreren, voegt u het FunctionsStartup assembly-kenmerk toe waarmee de typenaam wordt opgegeven die tijdens het opstarten wordt gebruikt.

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

In dit voorbeeld wordt het pakket Microsoft.Extensions.Http gebruikt dat is vereist voor het registreren van een HttpClient bij het opstarten.

Waarschuwingen

Een reeks registratiestappen wordt uitgevoerd vóór en nadat de runtime de opstartklasse heeft verwerkt. Houd daarom rekening met de volgende items:

  • De opstartklasse is alleen bedoeld voor installatie en registratie. Vermijd het gebruik van services die zijn geregistreerd bij het opstarten tijdens het opstartproces. Probeer bijvoorbeeld geen bericht in een logboek te registreren dat tijdens het opstarten wordt geregistreerd. Dit punt van het registratieproces is te vroeg om uw services beschikbaar te maken voor gebruik. Nadat de Configure methode is uitgevoerd, blijft de Functions-runtime aanvullende afhankelijkheden registreren, wat van invloed kan zijn op de werking van uw services.

  • De container voor afhankelijkheidsinjectie bevat alleen expliciet geregistreerde typen. De enige services die beschikbaar zijn als injecteerbare typen, zijn de services die in de methode worden Configure ingesteld. Als gevolg hiervan zijn functiesspecifieke typen zoals en niet beschikbaar tijdens BindingContext de installatie of als ExecutionContext injecteerbare typen.

Geïnjecteerde afhankelijkheden gebruiken

Constructorinjectie wordt gebruikt om uw afhankelijkheden beschikbaar te maken in een functie. Het gebruik van constructorinjectie vereist dat u geen statische klassen gebruikt voor geïnjecteerde services of voor uw functieklassen.

In het volgende voorbeeld wordt gedemonstreerd hoe de IMyService afhankelijkheden en HttpClient worden geïnjecteerd in een http-geactiveerde functie.

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

In dit voorbeeld wordt het pakket Microsoft.Extensions.Http gebruikt dat is vereist voor het registreren van een HttpClient bij het opstarten.

Levensduur van de service

Azure Functions-apps bieden dezelfde levensduur als ASP.NET afhankelijkheidsinjectie. Voor een Functions-app gedragen de verschillende levensduur van de service zich als volgt:

  • Tijdelijk: tijdelijke services worden gemaakt bij elke oplossing van de service.
  • Scoped: de levensduur van de scoped service komt overeen met de levensduur van de uitvoering van een functie. Services met bereik worden eenmaal per functie-uitvoering gemaakt. Latere aanvragen voor die service tijdens de uitvoering hergebruiken het bestaande service-exemplaar.
  • Singleton: de levensduur van de singleton-service komt overeen met de levensduur van de host en wordt opnieuw gebruikt voor functie-uitvoeringen op dat exemplaar. Singleton-levensduurservices worden aanbevolen voor verbindingen en clients, bijvoorbeeld DocumentClient of HttpClient exemplaren.

Bekijk of download een voorbeeld van verschillende levensduur van de service op GitHub.

Services voor logboekregistratie

Als u uw eigen provider voor logboekregistratie nodig hebt, registreert u een aangepast type als een exemplaar van , dat beschikbaar is via het ILoggerProvider Microsoft.Extensions.Logging.Abstractions NuGet-pakket.

Toepassings Insights wordt automatisch Azure Functions toegevoegd.

Waarschuwing

  • Voeg niet toe aan AddApplicationInsightsTelemetry() de servicesverzameling, waarmee services worden geregistreerd die conflicteren met services die door de omgeving worden geleverd.
  • Registreer uw eigen toepassing niet of als u de ingebouwde functionaliteit voor TelemetryConfiguration TelemetryClient toepassingsfuncties Insights gebruikt. Als u uw eigen exemplaar moet configureren, maakt u er een via de geïnjecteerde, zoals wordt weergegeven in Aangepaste TelemetryClient TelemetryConfiguration telemetrie voor logboeken in C#-functies.

ILogger <T> en ILoggerFactory

De host injecteert ILogger<T> en ILoggerFactory services in constructors. Deze nieuwe logboekregistratiefilters worden echter standaard gefilterd uit de functielogboeken. U moet het bestand host.json wijzigen om u aan te kunnen bij aanvullende filters en categorieën.

In het volgende voorbeeld wordt gedemonstreerd hoe u ILogger<HttpTrigger> een toevoegt met logboeken die aan de host worden blootgesteld.

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

            // ...
    }
}

In het volgende host.json voorbeeldbestand wordt het logboekfilter toegevoegd.

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

Zie Logboekniveaus configureren voor meer informatie over logboekniveaus.

Door functie-app geleverde services

De functiehost registreert veel services. De volgende services kunnen veilig worden gebruikt als afhankelijkheid in uw toepassing:

Servicetype Levensduur Beschrijving
Microsoft.Extensions.Configuration.IConfiguration Singleton Runtimeconfiguratie
Microsoft.Azure.WebJobs.Host.Executors.IHostIdProvider Singleton Verantwoordelijk voor het verstrekken van de id van het host-exemplaar

Als er andere services zijn waar u afhankelijk van wilt zijn, maakt u een probleem en stelt u deze voor op GitHub.

Hostservices overschrijven

Het overschrijven van services die door de host worden geleverd, wordt momenteel niet ondersteund. Als er services zijn die u wilt overschrijven, maakt u een probleem en stelt u deze voor GitHub.

Werken met opties en instellingen

Waarden die zijn gedefinieerd in app-instellingen zijn beschikbaar in een exemplaar, waarmee u IConfiguration app-instellingenwaarden kunt lezen in de opstartklasse.

U kunt waarden uit het exemplaar IConfiguration extraheren in een aangepast type. Als u de app-instellingen naar een aangepast type kopieert, kunt u uw services eenvoudig testen door deze waarden injecteerbaar te maken. Instellingen in het configuratie-exemplaar moeten eenvoudige sleutel-waardeparen zijn.

Houd rekening met de volgende klasse die een eigenschap bevat met de naam consistent met een app-instelling:

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

En een local.settings.json bestand dat de aangepaste instelling als volgt kan structureren:

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

Vanuit de methode kunt u waarden uit het exemplaar extraheren Startup.Configure in uw aangepaste type met behulp van de volgende IConfiguration code:

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

Als u Bind aanroept, worden waarden met overeenkomende eigenschapsnamen uit de configuratie gekopieerd naar het aangepaste exemplaar. De instantie met opties is nu beschikbaar in de IoC-container om in een functie te injecteren.

Het optiesobject wordt in de functie geïnjecteerd als een exemplaar van de algemene IOptions interface. Gebruik de Value eigenschap om toegang te krijgen tot de waarden in uw configuratie.

using System;
using Microsoft.Extensions.Options;

public class HttpTrigger
{
    private readonly MyOptions _settings;

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

Raadpleeg Het patroon Opties in ASP.NET Core voor meer informatie over het werken met opties.

Persoonlijke ASP.NET Core gebruiken

Wanneer u lokaal ontwikkelt, ASP.NET Core een Secret Manager-hulpprogramma waarmee u geheime gegevens buiten de hoofdmap van het project kunt opslaan. Het maakt het minder waarschijnlijk dat geheimen per ongeluk worden vastgelegd in broncodebeheer. Azure Functions Core Tools (versie 3.0.3233 of hoger) leest automatisch geheimen die zijn gemaakt door de ASP.NET Core Secret Manager.

Als u een .NET-Azure Functions om gebruikersgeheimen te gebruiken, moet u de volgende opdracht uitvoeren in de hoofdmap van het project.

dotnet user-secrets init

Gebruik vervolgens de dotnet user-secrets set opdracht om geheimen te maken of bij te werken.

dotnet user-secrets set MySecret "my secret value"

Als u toegang wilt krijgen tot waarden voor gebruikersgeheimen in de code van uw functie-app, gebruikt IConfiguration u of IOptions .

Configuratiebronnen aanpassen

Notitie

Aanpassing van configuratiebron is beschikbaar vanaf Azure Functions hostversies 2.0.14192.0 en 3.0.14191.0.

Als u aanvullende configuratiebronnen wilt opgeven, overschrijven u de methode in de klasse van ConfigureAppConfiguration uw StartUp functie-app.

In het volgende voorbeeld worden configuratiewaarden uit een basis en een optionele omgevingsspecifieke app-instellingenbestanden toegevoegd.

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

Voeg configuratieproviders toe aan ConfigurationBuilder de eigenschap van IFunctionsConfigurationBuilder . Zie Configuratie in ASP.NET Core voor meer informatie over het gebruik van configuratieproviders.

A FunctionsHostBuilderContext wordt verkregen van IFunctionsConfigurationBuilder.GetContext() . Gebruik deze context om de huidige omgevingsnaam op te halen en de locatie van configuratiebestanden in uw functie-app-map om te zetten.

Standaard worden configuratiebestanden zoals appsettings.json niet automatisch gekopieerd naar de uitvoermap van de functie-app. Werk het .csproj-bestand bij zodat het overeen komt met het volgende voorbeeld om ervoor te zorgen dat de bestanden worden gekopieerd.

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

Belangrijk

Voor functie-apps die worden uitgevoerd in het verbruiks- of Premium-abonnementen, kunnen wijzigingen in configuratiewaarden die worden gebruikt in triggers schaalfouten veroorzaken. Wijzigingen in deze eigenschappen door de klasse FunctionsStartup leiden tot een opstartfout voor de functie-app.

Volgende stappen

Zie de volgende resources voor meer informatie: