Verwenden der Abhängigkeitsinjektion in Azure Functions (.NET)
Azure Functions unterstützt das Softwareentwurfsmuster „Abhängigkeitsinjektion“ (Dependency Injection, DI). Damit kann eine Umkehrung der Steuerung (Inversion of Control, IoC) zwischen Klassen und ihren Abhängigkeiten erreicht werden.
Die Abhängigkeitsinjektion in Azure Functions basiert auf den .NET Core-Features für die Abhängigkeitsinjektion. Vertrautheit mit der .NET Core- Abhängigkeitsinjektion wird empfohlen. Es bestehen Unterschiede darin, wie Sie Abhängigkeiten überschreiben und wie Konfigurationswerte mit Azure Functions im Verbrauchstarif gelesen werden.
Die Unterstützung der Abhängigkeitsinjektion beginnt mit Azure Functions 2.x.
Abhängigkeitsinjektionsmuster unterscheiden sich abhängig davon, ob Ihre C#-Funktionen in-Process oder außerhalb des Prozessesausgeführt werden.
Wichtig
Die Anleitung in diesem Artikel gilt nur für Funktionen der C#-Klassenbibliothek, die in-Process mit der Laufzeit ausgeführt werden. Dieses benutzerdefinierte Abhängigkeitsinjektionsmodell gilt nicht für isolierte .NET-Funktionen, mit denen Sie .NET-Funktionen außerhalb des Prozesses ausführen können. Das isolierte .NET-Workerprozessmodell basiert auf regulären Abhängigkeitsinjektionsmustern von ASP.NET Core. Weitere Informationen finden Sie unter Abhängigkeitsinjektion in der Anleitung zum isolierten Workerprozess für .NET.
Voraussetzungen
Bevor Sie die Abhängigkeitsinjektion verwenden können, müssen Sie die folgenden NuGet-Pakete installieren:
Microsoft.NET.Sdk.Functions-Paket, Version 1.0.28 oder höher
Microsoft.Extensions.DependencyInjection (derzeit werden nur Versionen ab 2.x unterstützt)
Registrieren von Diensten
Um Dienste zu registrieren, erstellen Sie eine Methode zum Konfigurieren und Hinzufügen von Komponenten zu einer IFunctionsHostBuilder
-Instanz. Der Azure Functions-Host erstellt eine Instanz von IFunctionsHostBuilder
und übergibt diese direkt an Ihre Methode.
Warnung
Bei Funktions-Apps, die im Nutzungs- oder Premium-Plan ausgeführt werden, können Änderungen an Konfigurationswerten, die in Triggern verwendet werden, zu Skalierungsfehlern führen. Alle Änderungen an diesen Eigenschaften durch die FunctionsStartup
-Klasse führen zu einem Startfehler der Funktions-App.
Das Einschleusen von IConfiguration
kann zu unerwartetem Verhalten führen. Weitere Informationen zum Hinzufügen von Konfigurationsquellen finden Sie unter Anpassen von Konfigurationsquellen.
Fügen Sie zum Registrieren der Methode das FunctionsStartup
-Assembly-Attribut hinzu, mit dem der Typname angegeben wird, der beim Starten verwendet wird.
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 diesem Beispiel wird das Paket Microsoft.Extensions.Http verwendet, das beim Start HttpClient
registrieren muss.
Vorbehalte
Eine Reihe von Registrierungsschritten wird vor und nach dem Verarbeiten der Startup-Klasse ausgeführt. Berücksichtigen Sie daher die folgenden Punkte:
Die Startup-Klasse ist nur für Setup und Registrierung vorgesehen. Vermeiden Sie die Verwendung von Diensten, die beim Start während des Startvorgangs registriert werden. Versuchen Sie beispielsweise nicht, eine Nachricht in einer Protokollierung zu protokollieren, die während des Starts registriert wird. Dieser Zeitpunkt des Registrierungsprozesses ist zu früh, damit ihre Dienste zur Verwendung verfügbar sind. Nachdem die
Configure
-Methode ausgeführt wurde, registriert die Azure Functions-Laufzeit weiterhin zusätzliche Abhängigkeiten, die sich auf den Betrieb ihrer Dienste auswirken können.Der Container für die Abhängigkeitsinjektion enthält nur explizit registrierte Typen. Die einzigen Dienste, die als einschleusbare Typen verfügbar sind, sind diejenigen, die in der
Configure
-Methode eingerichtet werden. Folglich sind Azure Functions-spezifische Typen wieBindingContext
undExecutionContext
während des Setups oder als injizierbare Typen nicht verfügbar.Das Konfigurieren der ASP.NET-Authentifizierung wird nicht unterstützt. Der Functions-Host konfiguriert ASP.NET-Authentifizierungsdienste, um APIs ordnungsgemäß für wichtige Lebenszyklusvorgänge verfügbar zu machen. Andere Konfigurationen in einer benutzerdefinierten
Startup
-Klasse können diese Konfiguration außer Kraft setzen, was unbeabsichtigte Folgen verursacht. Beispielsweise kann das Aufrufen vonbuilder.Services.AddAuthentication()
die Authentifizierung zwischen dem Portal und dem Host unterbrechen, was Meldungen wie Azure Functions-Laufzeit ist nicht erreichbar auslöst.
Verwenden von eingefügten Abhängigkeiten
Die Konstruktorinjektion wird verwendet, um Ihre Abhängigkeiten in einer Funktion verfügbar zu machen. Bei Verwendung der Konstruktoreinschleusung dürfen für eingeschleuste Dienste oder für Ihre Funktionsklassen keine statischen Klassen verwendet werden.
Im folgenden Beispiel wird veranschaulicht, wie die Abhängigkeiten IMyService
und HttpClient
in eine per HTTP ausgelöste Funktion eingefügt werden.
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 diesem Beispiel wird das Paket Microsoft.Extensions.Http verwendet, das beim Start HttpClient
registrieren muss.
Dienstlebensdauer
Azure Functions-Apps bieten dieselbe Dienstlebensdauer wie die ASP.NET-Abhängigkeitsinjektion. Bei einer Funktions-App weisen die verschiedenen Dienstlebensdauern die folgenden Verhalten auf:
- Vorübergehend: Bei jeder Lösung des Diensts werden vorübergehende Dienste erstellt.
- Bereichsbezogen: Die bereichsbezogene Lebensdauer eines Diensts entspricht der Ausführungslebensdauer einer Funktion. Bereichsbezogene Dienste werden einmal pro Funktionsausführung erstellt. In späteren Anforderungen für diesen Dienst während der Ausführung wird die vorhandene Dienstinstanz wiederverwendet.
- Singleton: Die Lebensdauer eines Singletondiensts entspricht der Lebensdauer des Hosts und wird für Funktionsausführungen dieser Instanz wiederverwendet. Dienste mit Singleton-Lebensdauer werden für Verbindungen und Clients empfohlen, z. B. Instanzen von
DocumentClient
oderHttpClient
.
Sie können auf GitHub ein Beispiel für verschiedene Dienstlebensdauern anzeigen bzw. herunterladen.
Protokollierungsdienste
Wenn Sie einen eigenen Protokollierungsanbieter benötigen, registrieren Sie einen benutzerdefinierten Typ als eine Instanz von ILoggerProvider
(verfügbar über das NuGet-Paket Microsoft.Extensions.Logging.Abstractions).
Application Insights wird von Azure Functions automatisch hinzugefügt.
Warnung
- Fügen Sie
AddApplicationInsightsTelemetry()
, wodurch Dienste registriert werden, die zu Konflikten mit den von der Umgebung bereitgestellten Diensten führen können, nicht der Dienstsammlung hinzu. - Registrieren Sie keine eigene Instanz von
TelemetryConfiguration
oderTelemetryClient
, wenn Sie die integrierten Application Insights-Funktionen verwenden. Wenn Sie Ihre eigeneTelemetryClient
-Instanz konfigurieren müssen, erstellen Sie diese über die eingefügteTelemetryConfiguration
, wie in Protokollieren von benutzerdefinierter Telemetrie in C#-Funktionen gezeigt.
ILogger<T> und ILoggerFactory
Vom Host werden die Dienste ILogger<T>
und ILoggerFactory
in Konstruktoren eingefügt. Diese neuen Protokollierungsfilter werden jedoch standardmäßig aus den Funktionsprotokollen herausgefiltert. Sie müssen die host.json
-Datei ändern, um zusätzliche Filter und Kategorien verwenden zu können.
Im folgenden Beispiel wird ein Element vom Typ ILogger<HttpTrigger>
mit Protokollen hinzugefügt, die für den Host verfügbar gemacht werden:
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 der folgenden Beispieldatei host.json
wird der Protokollfilter hinzugefügt:
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
},
"logLevel": {
"MyNamespace.HttpTrigger": "Information"
}
}
}
Weitere Informationen zu Protokollgraden finden Sie unter Konfigurieren von Protokollgraden.
Dienste, die von Funktions-App bereitgestellt werden
Der Funktionshost registriert viele Dienste. Es ist sicher, die folgenden Dienste als Abhängigkeit in Ihrer Anwendung zu verwenden:
Diensttyp | Gültigkeitsdauer | BESCHREIBUNG |
---|---|---|
Microsoft.Extensions.Configuration.IConfiguration |
Singleton | Laufzeitkonfiguration |
Microsoft.Azure.WebJobs.Host.Executors.IHostIdProvider |
Singleton | Verantwortlich für die Bereitstellung der Hostinstanz-ID |
Erstellen Sie ein Issue, und schlagen Sie es auf GitHub vor, wenn Sie eine Abhängigkeit von anderen Diensten erstellen möchten.
Überschreiben von Hostdiensten
Das Überschreiben der vom Host bereitgestellten Dienste wird derzeit nicht unterstützt. Erstellen Sie ein Issue, und schlagen Sie es auf GitHub vor, falls andere Dienste vorhanden sind, die Sie überschreiben möchten.
Arbeiten mit Optionen und Einstellungen
Werte, die in App-Einstellungen definiert sind, sind in einer IConfiguration
-Instanz verfügbar, die es Ihnen ermöglicht, App-Einstellungswerte in der Startup-Klasse zu lesen.
Sie können Werte aus der IConfiguration
-Instanz in einen benutzerdefinierten Typ extrahieren. Wenn Sie App-Einstellungswerte in einen benutzerdefinierten Typ kopieren, können Sie Ihre Dienste mühelos testen, indem Sie diese Werte injizierbar gestalten. Die in die Konfigurationsinstanz eingelesenen Einstellungen müssen einfache Schlüssel/Wert-Paare sein. Bei Funktionen, die in einem Elastic Premium-Plan ausgeführt werden, dürfen Anwendungseinstellungsnamen nur Buchstaben, Zahlen (0-9
), Punkte (.
), Doppelpunkte (:
) und Unterstriche (_
) enthalten. Weitere Informationen finden Sie in den Überlegungen zu App-Einstellungen.
Beachten Sie die folgende Klasse, die eine Eigenschaft mit dem Namen „consistent“ mit einer App-Einstellung enthält:
public class MyOptions
{
public string MyCustomSetting { get; set; }
}
Sowie eine Datei local.settings.json
, die die benutzerdefinierte Einstellung möglicherweise wie folgt strukturiert:
{
"IsEncrypted": false,
"Values": {
"MyOptions:MyCustomSetting": "Foobar"
}
}
Innerhalb der Startup.Configure
-Methode können Sie Werte aus der IConfiguration
-Instanz mit dem folgenden Code in Ihren benutzerdefinierten Typ extrahieren:
builder.Services.AddOptions<MyOptions>()
.Configure<IConfiguration>((settings, configuration) =>
{
configuration.GetSection("MyOptions").Bind(settings);
});
Durch den Aufruf von Bind
werden Werte mit übereinstimmenden Eigenschaftsnamen aus der Konfiguration in die benutzerdefinierte Instanz kopiert. Die Optionsinstanz ist nun im IoC-Container zum Injizieren in eine Funktion verfügbar.
Das Optionsobjekt wird als Instanz der generischen IOptions
-Schnittstelle in die Funktion injiziert. Verwenden Sie die Value
-Eigenschaft, um auf die in Ihrer Konfiguration gefundenen Werte zuzugreifen.
using System;
using Microsoft.Extensions.Options;
public class HttpTrigger
{
private readonly MyOptions _settings;
public HttpTrigger(IOptions<MyOptions> options)
{
_settings = options.Value;
}
}
Weitere Informationen finden Sie unter Optionsmuster in ASP.NET Core.
Verwenden von geheimen ASP.NET Core-Benutzerschlüsseln
Wenn Sie Ihre App lokal entwickeln, bietet ASP.NET Core das Secret Manager-Tool, mit dem Sie Informationen zu Geheimnissen außerhalb des Projektstamms speichern können. Dadurch sinkt die Wahrscheinlichkeit, dass geheime Schlüssel versehentlich an die Quellcodeverwaltung übertragen werden. Azure Functions Core Tools (Version 3.0.3233 oder höher) liest automatisch geheime Schlüssel, die vom ASP.NET Core Secret Manager erstellt wurden.
Führen Sie den folgenden Befehl im Stammverzeichnis des .NET Azure Functions-Projekts aus, um es für die Verwendung von geheimen Benutzerschlüsseln zu konfigurieren.
dotnet user-secrets init
Verwenden Sie dann den Befehl dotnet user-secrets set
, um geheime Schlüssel zu erstellen oder zu aktualisieren.
dotnet user-secrets set MySecret "my secret value"
Verwenden Sie IConfiguration
oder IOptions
, um auf die Werte der geheimen Benutzerschlüssel in Ihrem Funktions-App-Code zuzugreifen.
Anpassen von Konfigurationsquellen
Überschreiben Sie zum Angeben zusätzlicher Konfigurationsquellen die ConfigureAppConfiguration
-Methode in der StartUp
-Klasse Ihrer Funktions-App.
Im folgenden Beispiel werden Konfigurationswerte aus einer Basisdatei und einer Datei mit optionalen umgebungsspezifischen App-Einstellungen hinzugefügt.
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)
{
}
}
Fügen Sie der Eigenschaft ConfigurationBuilder
von IFunctionsConfigurationBuilder
Konfigurationsanbieter hinzu. Weitere Informationen zur Verwendung von Konfigurationsanbietern finden Sie unter Konfiguration in ASP.NET Core.
FunctionsHostBuilderContext
wird aus IFunctionsConfigurationBuilder.GetContext()
abgerufen. Verwenden Sie diesen Kontext, um den aktuellen Umgebungsnamen abzurufen und den Speicherort der Konfigurationsdateien in Ihrem Funktions-App-Ordner aufzulösen.
Standardmäßig werden Konfigurationsdateien wie appsettings.json
nicht automatisch in den Ausgabeordner der Funktions-App kopiert. Aktualisieren Sie Ihre .csproj
-Datei dem folgenden Beispiel entsprechend, um sicherzustellen, dass die Dateien kopiert werden.
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="appsettings.Development.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
Nächste Schritte
Weitere Informationen finden Sie in den folgenden Ressourcen: