Entwickeln von C#-Klassenbibliotheksfunktionen mithilfe von Azure Functions

Dieser Artikel ist eine Einführung in die Entwicklung von Azure Functions durch Verwenden von C# in .NET-Klassenbibliotheken.

Wichtig

Dieser Artikel unterstützt Funktionen der .NET-Klassenbibliothek, die prozessintern mit der Runtime ausgeführt werden. Functions unterstützt auch .NET 5.x, indem die C#-Funktionen prozessextern ausgeführt und von der Runtime isoliert werden. Weitere Informationen finden Sie unter .NET-isolierte Prozessfunktionen.

Für C#-Entwickler sind möglicherweise auch folgende Artikel interessant:

Erste Schritte Konzepte Geführte Tutorials/Beispiele

Azure Functions unterstützt die Programmiersprachen C# und C#-Skript. Wenn Sie nach Anleitungen zum Verwenden von C# im Azure-Portal suchen, lesen Sie C#-Skriptentwicklerreferenz (C#-Skript, CSX) zu Azure Functions.

Unterstützte Versionen

Versionen der Functions-Laufzeit funktionieren mit bestimmten Versionen von .NET. Weitere Informationen zu den Functions-Versionen finden Sie unter Übersicht über die Runtimeversionen von Azure Functions. Die Versionsunterstützung hängt davon ab, ob Ihre Funktionen prozessintern oder prozessextern (isoliert) ausgeführt werden.

In der folgenden Tabelle sind die höchsten .NET Core- bzw. .NET Framework-Versionen aufgeführt, die mit einer bestimmten Version von Functions verwendet werden können.

Version der Functions-Laufzeit In-Process
(.NET-Klassenbibliothek)
Out-of-Process
(Isolierte .NET-Ausführung)
Functions 4.x1 .NET 6.0 (Vorschau) .NET 6.0 (Vorschau)
Functions 3.x .NET Core 3.1 .NET 5.0
Functions 2.x .NET Core 2.12
Functions 1.x .NET Framework 4.8

1 Azure Functions bietet experimentelle Unterstützung für die Ausführung Ihrer Funktionen im Vorschaurelease von .NET 6.0. Diese Vorabversion wird nicht offiziell unterstützt. Weitere Informationen finden Sie auf der Seite zur frühen Vorschauversion von Azure Functions v4.
2 Weitere Informationen finden Sie unter Überlegungen zu Functions-Versionen 2.x.

Aktuelle Informationen zu Azure Functions-Releases (einschließlich Informationen zur Entfernung bestimmter älterer Nebenversionen) finden Sie unter Azure App Service-Ankündigungen.

Überlegungen zu Functions-Versionen 2.x

Funktions-Apps für die neueste 2.x-Version (~2) werden automatisch upgegradet, damit sie auf .NET Core 3.1 ausgeführt werden können. Aufgrund von Breaking Changes zwischen den .NET Core-Versionen können nicht alle Apps, die für .NET Core 2.2 entwickelt und kompiliert wurden, sicher auf .NET Core 3.1 upgegradet werden. Sie können dieses Upgrade deaktivieren, indem Sie Ihre Funktions-App an ~2.0 anheften. Functions erkennt auch inkompatible APIs und kann Ihre App an ~2.0 anheften, um eine fehlerhafte Ausführung unter .NET Core 3.1 zu verhindern.

Hinweis

Wenn Ihre Funktions-App an ~2.0 angeheftet ist und Sie dieses Versionsziel in ~2 ändern, wird Ihre Funktions-App möglicherweise unterbrochen. Wenn Sie mithilfe von ARM-Vorlagen bereitstellen, überprüfen Sie die Version in Ihren Vorlagen. Wenn dies der Fall ist, ändern Sie die Zielversion zurück in ~2.0, und beheben Sie Kompatibilitätsprobleme.

Funktions-Apps für ~2.0 funktionieren weiterhin unter .NET Core 2.2. Für diese Version von .NET Core werden keine Sicherheitsupdates und keine sonstigen Wartungsupdates mehr durchgeführt. Weitere Informationen finden Sie auf dieser Ankündigungsseite.

Sie sollten daran arbeiten, dass Ihre Funktionen so bald wie möglich mit .NET Core 3.1 kompatibel sind. Nachdem Sie diese Probleme behoben haben, ändern Sie Ihre Version wieder in ~2, oder führen Sie ein Upgrade auf ~3 durch. Weitere Informationen zu Zielversionen der Functions-Runtime finden Sie unter Einstellen von Runtimeversionen von Azure Functions als Ziel.

Wenn Sie die Funktion unter Linux in einem Premium- oder Dedicated-Plan (App Service) ausführen, können Sie Ihre Version anheften, indem Sie stattdessen ein bestimmtes Image als Ziel festlegen. Legen Sie hierzu die Sitekonfigurationseinstellung linuxFxVersion auf DOCKER|mcr.microsoft.com/azure-functions/dotnet:2.0.14786-appservice fest. Weitere Informationen zum Festlegen von linuxFxVersion finden Sie unter Manuelle Versionsupdates unter Linux.

Funktionsklassenbibliotheks-Projekt

In Visual Studio wird mit der Azure Functions-Projektvorlage ein C#-Klassenbibliotheksprojekt erstellt, das die folgenden Dateien enthält:

  • host.json: Speichert Konfigurationseinstellungen, die sich auf alle Funktionen im Projekt auswirken, wenn es lokal oder in Azure ausgeführt wird.
  • local.settings.json: Speichert App-Einstellungen und Verbindungszeichenfolgen, die verwendet werden, wenn das Projekt lokal ausgeführt wird. Diese Datei enthält Geheimnisse und wird nicht in Ihrer Funktions-App in Azure veröffentlicht. Gehen Sie stattdessen so vor, dass Sie Ihrer Funktions-App App-Einstellungen hinzufügen.

Wenn Sie das Projekt erstellen, wird im Buildausgabeverzeichnis eine Ordnerstruktur generiert, die weitgehend so aussieht wie das folgende Beispiel:

<framework.version>
 | - bin
 | - MyFirstFunction
 | | - function.json
 | - MySecondFunction
 | | - function.json
 | - host.json

Dieses Verzeichnis wird in Ihrer Funktions-App in Azure bereitgestellt. Die in Version 2.x der Functions-Runtime erforderlichen Bindungserweiterungen werden dem Projekt als NuGet-Pakete hinzugefügt.

Wichtig

Im Buildprozess wird für jede Funktion eine Datei vom Typ function.json erstellt. Die Datei function.json ist nicht für die direkte Bearbeitung vorgesehen. Sie können weder die Bindungskonfiguration ändern noch die Funktion deaktivieren, indem Sie diese Datei bearbeiten. Informationen zum Deaktivieren einer Funktion finden Sie unter Gewusst wie: Deaktivieren von Funktionen.

Methoden, die als Funktionen erkannt werden

In einer Klassenbibliothek ist eine Funktion eine statische Methode mit einem Funktionsnamen (FunctionName) und einem Trigger-Attribut, wie im folgenden Beispiel gezeigt:

public static class SimpleExample
{
    [FunctionName("QueueTrigger")]
    public static void Run(
        [QueueTrigger("myqueue-items")] string myQueueItem, 
        ILogger log)
    {
        log.LogInformation($"C# function processed: {myQueueItem}");
    }
} 

Das Attribut FunctionName kennzeichnet die Methode als Funktionseinstiegspunkt. Der Name muss innerhalb eines Projekts eindeutig sein, mit einem Buchstaben beginnen und darf nur Buchstaben, Ziffern, _ und - enthalten. Bis zu 127 Zeichen sind zulässig. Projektvorlagen erstellen oft eine Methode namens Run, aber der Name der Methode kann ein beliebiger gültiger C#-Methodennamen sein.

Das Trigger-Attribut gibt den Triggertyp an und bindet die Eingabedaten an einen Methodenparameter. Die Beispielfunktion wird durch eine Warteschlangennachricht ausgelöst, und die Warteschlangennachricht wird im myQueueItem-Parameter an die Methode übergeben.

Methodensignaturparameter

Die Methodensignatur kann andere Parameter als den mit dem Triggerattribut verwendeten Parameter enthalten. Hier sind einige weitere Parameter aufgeführt, die Sie verwenden können:

Die Reihenfolge der Parameter in der Funktionssignatur spielt keine Rolle. Beispielsweise können Sie Triggerparameter für Bindungen voran- oder nachstellen und den Parameter „logger“ vor oder nach Trigger- oder Bindungsparametern anordnen.

Ausgabebindungen

Eine Funktion kann über keine oder eine Ausgabebindung verfügen. Dies wird mithilfe von Ausgabeparametern definiert.

Im folgenden Beispiel wird das vorhergehende Beispiel geändert, indem eine Ausgabe-Warteschlangenbindung mit dem Namen myQueueItemCopy hinzugefügt wird. Die Funktion schreibt den Inhalt der Meldung, die die Funktion auslöst, in eine neue Warteschlangenmeldung in einer anderen Warteschlange.

public static class SimpleExampleWithOutput
{
    [FunctionName("CopyQueueMessage")]
    public static void Run(
        [QueueTrigger("myqueue-items-source")] string myQueueItem, 
        [Queue("myqueue-items-destination")] out string myQueueItemCopy,
        ILogger log)
    {
        log.LogInformation($"CopyQueueMessage function processed: {myQueueItem}");
        myQueueItemCopy = myQueueItem;
    }
}

Werte, die Ausgabebindungen zugewiesen sind, werden geschrieben, wenn die Funktion vorhanden ist. Sie können in einer Funktion mehr als eine Ausgabebindung verwenden, indem Sie einfach mehreren Ausgabeparametern Werte zuweisen.

In den Artikeln zu den Bindungsverweisen (z. B. Speicherwarteschlangen) wird erläutert, welche Parametertypen Sie mit Trigger-, Eingabe- oder Ausgabebindungsattributen verwenden können.

Beispiel für Bindungsausdrücke

Mit dem folgenden Code wird der Name der zu überwachenden Warteschlange für eine App-Einstellung abgerufen, und der Erstellungszeitpunkt der Warteschlangennachricht ist im Parameter insertionTime enthalten.

public static class BindingExpressionsExample
{
    [FunctionName("LogQueueMessage")]
    public static void Run(
        [QueueTrigger("%queueappsetting%")] string myQueueItem,
        DateTimeOffset insertionTime,
        ILogger log)
    {
        log.LogInformation($"Message content: {myQueueItem}");
        log.LogInformation($"Created at: {insertionTime}");
    }
}

Automatisch generierte function.json-Datei

Im Buildprozess wird eine function.json-Datei in einem Funktionsordner im Ordner für Builds erstellt. Wie bereits erwähnt ist diese Datei nicht für die direkte Bearbeitung vorgesehen. Sie können weder die Bindungskonfiguration ändern noch die Funktion deaktivieren, indem Sie diese Datei bearbeiten.

Der Zweck dieser Datei besteht darin, Informationen für den Skalierungscontroller bereitzustellen, die dieser für Skalierungsentscheidungen hinsichtlich des Verbrauchsplans verwenden kann. Aus diesem Grund weist die Datei nur Triggerinformationen und keine Eingabe-/Ausgabebindungen auf.

Die generierte function.json-Datei enthält eine configurationSource-Eigenschaft, die der Runtime mitteilt, dass sie statt der function.json-Konfiguration die .NET Attribute für Bindungen verwenden soll. Hier sehen Sie ein Beispiel:

{
  "generatedBy": "Microsoft.NET.Sdk.Functions-1.0.0.0",
  "configurationSource": "attributes",
  "bindings": [
    {
      "type": "queueTrigger",
      "queueName": "%input-queue-name%",
      "name": "myQueueItem"
    }
  ],
  "disabled": false,
  "scriptFile": "..\\bin\\FunctionApp1.dll",
  "entryPoint": "FunctionApp1.QueueTrigger.Run"
}

Microsoft.NET.Sdk.Functions

Die Erstellung der function.json-Datei wird mit dem NuGet-Paket Microsoft.NET.Sdk.Functions ausgeführt.

Dasselbe Paket wird für die Versionen 1.x und 2.x der Functions-Runtime verwendet. Ein 1.x-Projekt unterscheidet sich durch das Zielframework von einem 2.x-Projekt. Hier sind die relevanten Teile von CSPROJ-Dateien aufgeführt, die verschiedene Zielframeworks mit demselben Sdk-Paket zeigen:

<PropertyGroup>
  <TargetFramework>netcoreapp2.1</TargetFramework>
  <AzureFunctionsVersion>v2</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
  <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.8" />
</ItemGroup>

Unter den Sdk-Paketabhängigkeiten befinden sich Auslöser und Bindungen. Ein 1.x-Projekt verweist auf 1.x-Auslöser und -Bindungen, da diese Auslöser und Bindungen für das .NET Framework ausgelegt sind, während 2.x-Auslöser und -Bindungen für .NET Core ausgelegt sind.

Das Sdk-Paket hängt außerdem von Newtonsoft.Json und indirekt von WindowsAzure.Storage ab. Diese Abhängigkeiten stellen sicher, dass Ihr Projekt die Versionen dieser Pakete verwendet, die mit der Functions-Runtime-Version funktionieren, auf die das Projekt ausgelegt ist. Beispiel: Newtonsoft.Json weist Version 11 für .NET Framework 4.6.1 auf, die Functions-Runtime, die auf .NET Framework 4.6.1 ausgelegt ist, ist jedoch nur mit Newtonsoft.Json 9.0.1 kompatibel. Daher muss Ihr Funktionscode in diesem Projekt auch Newtonsoft.Json 9.0.1 verwenden.

Der Quellcode für Microsoft.NET.Sdk.Functions ist im GitHub-Repository azure-functions-vs-build-sdk verfügbar.

Lokale Runtimeversion

Visual Studio verwendet Azure Functions Core Tools zum Ausführen von Functions-Projekten auf Ihrem lokalen Computer. Core Tools ist eine Befehlszeilenschnittstelle für die Functions-Runtime.

Wenn Sie die Core Tools mithilfe des Windows Installer-Pakets (MSI) oder npm installieren, wirkt sich dies nicht auf die von Visual Studio verwendete Core Tools-Version aus. Für die Functions-Runtime-Version 1.x speichert Visual Studio Core Tools-Versionen in %USERPROFILE%\AppData\Local\Azure.Functions.Cli und verwendet die aktuelle dort gespeicherte Version. Für Function 2.x ist Core Tools in der Erweiterung Azure Functions und WebJobs Tools enthalten. Sie können sowohl für 1.x als auch 2.x anzeigen, welche Version in der Konsolenausgabe verwendet wird, wenn Sie ein Functions-Projekt ausführen:

[3/1/2018 9:59:53 AM] Starting Host (HostId=contoso2-1518597420, Version=2.0.11353.0, ProcessId=22020, Debug=False, Attempt=0, FunctionsExtensionVersion=)

ReadyToRun

Sie können ihre Funktions-App als ReadyToRun-Binärdateien kompilieren. ReadyToRun ist eine Form der Vorabkompilierung, die zur Optimierung der Startleistung beitragen und die Auswirkungen eines Kaltstarts bei Ausführung in einem Verbrauchstarif reduzieren kann.

ReadyToRun ist in .NET 3.0 verfügbar und setzt Azure Functions Runtimeversion 3.0 voraus.

Um Ihr Projekt als „ReadyToRun“ zu kompilieren, aktualisieren Sie die Projektdatei, indem Sie die Elemente <PublishReadyToRun> und <RuntimeIdentifier> hinzufügen. Im Folgenden finden Sie die Konfiguration für die Veröffentlichung in einer Windows 32-Bit-Funktions-App.

<PropertyGroup>
  <TargetFramework>netcoreapp3.1</TargetFramework>
  <AzureFunctionsVersion>v3</AzureFunctionsVersion>
  <PublishReadyToRun>true</PublishReadyToRun>
  <RuntimeIdentifier>win-x86</RuntimeIdentifier>
</PropertyGroup>

Wichtig

ReadyToRun unterstützt derzeit keine Kreuzkompilierung. Sie müssen Ihre App auf derselben Plattform erstellen, auf der sich auch das Bereitstellungsziel befindet. Achten Sie auch auf die „Bitanzahl“, die in ihrer Funktions-App konfiguriert wird. Wenn Ihre Funktions-App in Azure z. B. mit Windows 64-Bit konfiguriert wird, müssen Sie Ihre App unter Windows mit win-x64 als Runtimebezeichner kompilieren.

Sie können Ihre App mit ReadyToRun auch über die Befehlszeile erstellen. Weitere Informationen finden Sie unter der Option -p:PublishReadyToRun=true in dotnet publish.

Unterstützte Typen für Bindungen

Jede Bindung hat ihre eigenen unterstützten Typen. Beispielsweise kann ein Blobtriggerattribut auf einen Zeichenfolgeparameter, einen POCO-Parameter, einen CloudBlockBlob-Parameter oder einen von mehreren anderen unterstützten Typen angewendet werden. Im Bindungsreferenzartikel für Blobbindungen sind alle unterstützten Parametertypen aufgelistet. Weitere Informationen hierzu finden Sie unter Trigger und Bindungen und in den Bindungsreferenzdokumenten für jeden Bindungstyp.

Tipp

Wenn Sie die HTTP- oder WebHook-Bindungen verwenden möchten, vermeiden Sie die Portauslastung, die durch nicht ordnungsgemäße Instanziierung von HttpClient verursacht werden kann. Weitere Informationen finden Sie unter How to manage connections in Azure Functions (Verwalten von Verbindungen in Azure Functions).

Binden an den Rückgabewert einer Methode

Sie können einen Rückgabewert einer Methode für eine Ausgabebindung nutzen, indem Sie das Attribut auf den Rückgabewert einer Methode anwenden. Beispiele finden Sie unter Konzepte für Azure Functions-Trigger und -Bindungen.

Verwenden Sie den Rückgabewert nur dann, wenn eine erfolgreiche Ausführung der Funktion immer einen Rückgabewert ergibt, der an die Ausgabebindung übergeben werden soll. Verwenden Sie andernfalls, wie im folgenden Abschnitt gezeigt, ICollector oder IAsyncCollector.

Schreiben von mehreren Ausgabewerten

Verwenden Sie die Typen ICollector oder IAsyncCollector in folgenden Fällen: 1. um mehrere Werte in eine Ausgabebindung zu schreiben oder 2. wenn ein erfolgreicher Funktionsaufruf möglicherweise keinen übergebbaren Wert für die Ausgabebindung ergibt. Diese Typen stellen lesegeschützte Sammlungen dar, die nach Durchführung der Methode in die Ausgabebindung geschrieben werden.

In diesem Beispiel werden mehrere Warteschlangennachrichten mit ICollector in die gleiche Warteschlange geschrieben:

public static class ICollectorExample
{
    [FunctionName("CopyQueueMessageICollector")]
    public static void Run(
        [QueueTrigger("myqueue-items-source-3")] string myQueueItem,
        [Queue("myqueue-items-destination")] ICollector<string> myDestinationQueue,
        ILogger log)
    {
        log.LogInformation($"C# function processed: {myQueueItem}");
        myDestinationQueue.Add($"Copy 1: {myQueueItem}");
        myDestinationQueue.Add($"Copy 2: {myQueueItem}");
    }
}

Async

Um eine Funktion asynchron auszuführen, verwenden Sie das async-Schlüsselwort, und geben Sie ein Task-Objekt zurück.

public static class AsyncExample
{
    [FunctionName("BlobCopy")]
    public static async Task RunAsync(
        [BlobTrigger("sample-images/{blobName}")] Stream blobInput,
        [Blob("sample-images-copies/{blobName}", FileAccess.Write)] Stream blobOutput,
        CancellationToken token,
        ILogger log)
    {
        log.LogInformation($"BlobCopy function processed.");
        await blobInput.CopyToAsync(blobOutput, 4096, token);
    }
}

Sie können keine out-Parameter in asynchronen Funktionen verwenden. Für Ausgabebindungen verwenden Sie stattdessen Funktionsrückgabewert oder Sammlerobjekt.

Abbruchtoken

Eine Funktion kann einen CancellationToken-Parameter annehmen, der es dem Betriebssystem ermöglicht, den Code vor dem Beenden der Funktion zu benachrichtigen. Sie können diese Benachrichtigung verwenden, um sicherzustellen, dass die Funktion nicht auf eine Weise unerwartet beendet wird, die die Daten in einem inkonsistenten Zustand hinterlässt.

Das folgende Beispiel zeigt, wie Sie nach einer bevorstehenden Beendigung einer Funktion suchen.

public static class CancellationTokenExample
{
    public static void Run(
        [QueueTrigger("inputqueue")] string inputText,
        TextWriter logger,
        CancellationToken token)
    {
        for (int i = 0; i < 100; i++)
        {
            if (token.IsCancellationRequested)
            {
                logger.WriteLine("Function was cancelled at iteration {0}", i);
                break;
            }
            Thread.Sleep(5000);
            logger.WriteLine("Normal processing for queue message={0}", inputText);
        }
    }
}

Protokollierung

In Ihrem Funktionscode können Sie die Ausgabe in Protokolle schreiben, die in Application Insights als Ablaufverfolgungen angezeigt werden. Die empfohlene Vorgehensweise zum Schreiben in die Protokolle besteht darin, einen Parameter vom Typ ILogger hinzuzufügen, der in der Regel log heißt. In Version 1.x der Functions-Runtime wurde TraceWriter verwendet. Dadurch wurde ebenfalls in Application Insights geschrieben, aber es wurde keine strukturierte Protokollierung unterstützt. Verwenden Sie nicht Console.Write zum Schreiben der Protokolle, da diese Daten von Application Insights nicht aufgezeichnet werden.

ILogger

Fügen Sie in Ihrer Funktionsdefinition den Parameter ILogger ein, der strukturierte Protokollierung unterstützt.

Mit einem ILogger-Objekt rufen Sie Log<level>-Erweiterungsmethoden in ILogger auf, um Protokolle zu erstellen. Mit dem folgenden Code werden Protokolle vom Typ Information mit der Kategorie Function.<YOUR_FUNCTION_NAME>.User. geschrieben.

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, ILogger logger)
{
    logger.LogInformation("Request for item with key={itemKey}.", id);

Weitere Informationen zur Implementierung von ILogger in Functions finden Sie unter Sammeln von Telemetriedaten. Bei Kategorien mit dem Präfix Function wird angenommen, dass Sie eine ILogger-Instanz verwenden. Wenn Sie stattdessen eine ILogger<T>-Instanz verwenden, kann der Kategoriename stattdessen auf T basieren.

Strukturierte Protokollierung

Die Reihenfolge der Platzhalter, nicht der Namen, bestimmt, welche Parameter in der Protokollnachricht verwendet werden. Angenommen, Sie verwenden den folgenden Code:

string partitionKey = "partitionKey";
string rowKey = "rowKey";
logger.LogInformation("partitionKey={partitionKey}, rowKey={rowKey}", partitionKey, rowKey);

Wenn Sie die gleiche Nachrichtenzeichenfolge beibehalten und die Reihenfolge der Parameter umkehren, befinden sich die Werte im resultierenden Nachrichtentext an den falschen Stellen.

Platzhalter werden auf diese Weise verarbeitet, damit Sie die strukturierte Protokollierung durchführen können. Application Insights speichert die Name/Wert-Paare für Parameter und die Nachrichtenzeichenfolge. Das Ergebnis ist, dass die Nachrichtenargumente zu Feldern werden, anhand denen Sie Abfragen durchführen können.

Wenn Ihr Methodenaufruf für die Protokollierung wie im vorherigen Beispiel aussieht, können Sie das Feld customDimensions.prop__rowKey abfragen. Durch das Hinzufügen des Präfix prop__ soll sichergestellt werden, dass es zwischen den Feldern, die von der Runtime hinzugefügt werden, und Feldern, die von Ihrem Funktionscode hinzugefügt werden, nicht zu Konflikten kommt.

Sie können auch die ursprüngliche Nachrichtenzeichenfolge abfragen, indem Sie auf das Feld customDimensions.prop__{OriginalFormat} verweisen.

Hier ist eine JSON-Beispieldarstellung von customDimensions-Daten angegeben:

{
  "customDimensions": {
    "prop__{OriginalFormat}":"C# Queue trigger function processed: {message}",
    "Category":"Function",
    "LogLevel":"Information",
    "prop__message":"c9519cbf-b1e6-4b9b-bf24-cb7d10b1bb89"
  }
}

Protokollieren benutzerdefinierter Telemetriedaten

Es gibt eine Functions-spezifische Version des Application Insights SDK, mit der Sie benutzerdefinierte Telemetriedaten von ihren Funktionen an Application Insights senden können: Microsoft.Azure.WebJobs.Logging.ApplicationInsights. Verwenden Sie den folgenden Befehl in der Eingabeaufforderung, um das folgende Paket zu installieren:

dotnet add package Microsoft.Azure.WebJobs.Logging.ApplicationInsights --version <VERSION>

Ersetzen <VERSION> in diesem Befehl durch eine Version dieses Pakets, die Ihre installierte Version von Microsoft.Azure.WebJobs unterstützt.

Im folgenden C#-Beispiel wird die benutzerdefinierte Telemetrie-API verwendet. Das Beispiel gilt für eine .NET-Klassenbibliothek, aber der Application Insights-Code ist für C#-Skript identisch.

Die Runtime ab Version 2.x verwendet neuere Features in Application Insights, um die Telemetrie automatisch mit dem aktuellen Vorgang zu korrelieren. Es ist nicht erforderlich, für den Vorgang die Felder Id, ParentId oder Name festzulegen.

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

using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.ApplicationInsights.Extensibility;
using System.Linq;

namespace functionapp0915
{
    public class HttpTrigger2
    {
        private readonly TelemetryClient telemetryClient;

        /// Using dependency injection will guarantee that you use the same configuration for telemetry collected automatically and manually.
        public HttpTrigger2(TelemetryConfiguration telemetryConfiguration)
        {
            this.telemetryClient = new TelemetryClient(telemetryConfiguration);
        }

        [FunctionName("HttpTrigger2")]
        public Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)]
            HttpRequest req, ExecutionContext context, ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");
            DateTime start = DateTime.UtcNow;

            // Parse query parameter
            string name = req.Query
                .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
                .Value;

            // Write an event to the customEvents table.
            var evt = new EventTelemetry("Function called");
            evt.Context.User.Id = name;
            this.telemetryClient.TrackEvent(evt);

            // Generate a custom metric, in this case let's use ContentLength.
            this.telemetryClient.GetMetric("contentLength").TrackValue(req.ContentLength);

            // Log a custom dependency in the dependencies table.
            var dependency = new DependencyTelemetry
            {
                Name = "GET api/planets/1/",
                Target = "swapi.co",
                Data = "https://swapi.co/api/planets/1/",
                Timestamp = start,
                Duration = DateTime.UtcNow - start,
                Success = true
            };
            dependency.Context.User.Id = name;
            this.telemetryClient.TrackDependency(dependency);

            return Task.FromResult<IActionResult>(new OkResult());
        }
    }
}

In diesem Beispiel werden die benutzerdefinierten Metrikdaten vom Host aggregiert, bevor sie an die Tabelle „customMetrics“ gesendet werden. Weitere Informationen finden Sie in der Dokumentation zu GetMetric in Application Insights.

Bei der lokalen Ausführung müssen Sie die Einstellung APPINSIGHTS_INSTRUMENTATIONKEY mit dem Application Insights-Schlüssel zur Datei local.settings.json hinzufügen.

Vermeiden Sie es, TrackRequest oder StartOperation<RequestTelemetry> aufzurufen, da in diesem Fall für einen Funktionsaufruf doppelte Anforderungen angezeigt werden. Mit der Functions-Laufzeit werden Anforderungen automatisch nachverfolgt.

Legen Sie nicht telemetryClient.Context.Operation.Id fest. Diese globale Einstellung führt zu falschen Korrelationen, wenn viele Funktionen gleichzeitig ausgeführt werden. Erstellen Sie stattdessen eine neue Telemetrieinstanz (DependencyTelemetry, EventTelemetry), und ändern Sie die Context-Eigenschaft. Übergeben Sie in der Telemetrie-Instanz dann die entsprechende Track-Methode TelemetryClient (TrackDependency(), TrackEvent(), TrackMetric()). Durch diese Methode wird sichergestellt, dass die Telemetrie die richtigen Korrelationsdetails für den aktuellen Funktionsaufruf enthält.

Umgebungsvariablen

Verwenden Sie System.Environment.GetEnvironmentVariablezum Abrufen einer Umgebungsvariablen oder zum Abrufen des Werts einer App-Einstellung, wie im folgenden Codebeispiel zu sehen:

public static class EnvironmentVariablesExample
{
    [FunctionName("GetEnvironmentVariables")]
    public static void Run([TimerTrigger("0 */5 * * * *")]TimerInfo myTimer, ILogger log)
    {
        log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
        log.LogInformation(GetEnvironmentVariable("AzureWebJobsStorage"));
        log.LogInformation(GetEnvironmentVariable("WEBSITE_SITE_NAME"));
    }

    private static string GetEnvironmentVariable(string name)
    {
        return name + ": " +
            System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
    }
}

App-Einstellungen können sowohl beim lokalen Entwickeln als auch bei der Ausführung unter Azure aus Umgebungsvariablen gelesen werden. Beim lokalen Entwickeln kommen App-Einstellungen aus der Values-Sammlung in der Datei local.settings.json. In beiden Umgebungen, lokal und Azure, ruft GetEnvironmentVariable("<app setting name>") den Wert der benannten App-Einstellung ab. Bei der lokalen Ausführung würde beispielsweise „My Site Name“ zurückgegeben, wenn Ihre local.settings.json-Datei { "Values": { "WEBSITE_SITE_NAME": "My Site Name" } } enthält.

Die Eigenschaft System.Configuration.ConfigurationManager.AppSettings ist eine alternative API zum Abrufen von Werten einer App-Einstellung, jedoch wird die hier gezeigte Verwendung von GetEnvironmentVariable empfohlen.

Binden zur Laufzeit

In C# und anderen .NET-Sprachen können Sie ein imperatives Bindungsmuster verwenden, im Gegensatz zu den deklarativen Bindungen in Attributen. Imperative Bindung eignet sich, wenn Bindungsparameter zur Laufzeit statt zur Entwurfszeit berechnet werden müssen. Mit diesem Muster ist die Bindung an unterstützte Eingabe- und Ausgabebindungen direkt im Funktionscode möglich.

Definieren Sie eine imperative Bindung wie folgt:

  • Schließen Sie für die gewünschten imperativen Bindungen kein Attribut in die Funktionssignatur ein.

  • Übergeben Sie den Eingabeparameter Binder binder oder IBinder binder.

  • Verwenden Sie das folgende C#-Muster, um die Datenbindung auszuführen.

    using (var output = await binder.BindAsync<T>(new BindingTypeAttribute(...)))
    {
        ...
    }
    

    BindingTypeAttribute ist das .NET-Attribut, das die Bindung definiert, und T ist ein Eingabe- oder Ausgabetyp, der von diesem Bindungstyp unterstützt wird. T darf kein out-Parametertyp sein (wie etwa out JObject). Die ausgehende Bindung für die Tabelle „Mobile Apps“ unterstützt z. B. sechs Ausgabetypen, Sie können aber nur ICollector<T> oder IAsyncCollector<T> mit imperativer Bindung verwenden.

Beispiel mit einem einzigen Attribut

Mit dem folgenden Beispielcode wird eine ausgehende Speicherblob-Bindung mit einem Blobpfad erstellt, der zur Laufzeit definiert wird. Dann wird eine Zeichenfolge in das Blob geschrieben.

public static class IBinderExample
{
    [FunctionName("CreateBlobUsingBinder")]
    public static void Run(
        [QueueTrigger("myqueue-items-source-4")] string myQueueItem,
        IBinder binder,
        ILogger log)
    {
        log.LogInformation($"CreateBlobUsingBinder function processed: {myQueueItem}");
        using (var writer = binder.Bind<TextWriter>(new BlobAttribute(
                    $"samples-output/{myQueueItem}", FileAccess.Write)))
        {
            writer.Write("Hello World!");
        };
    }
}

BlobAttribute definiert die Eingabe- oder Ausgabebindung für den Speicherblob, und TextWriter ist ein unterstützter Ausgabenbindungstyp.

Beispiel für mehrere Attribute

Im vorherigen Beispiel wird die App-Einstellung für die Verbindungszeichenfolge (AzureWebJobsStorage) des Hauptspeicherkontos der Funktions-App abgerufen. Sie können eine benutzerdefinierte App-Einstellung angeben, die für das Storage-Konto verwendet werden soll, indem Sie StorageAccountAttribute hinzufügen und das Attributarray an BindAsync<T>() übergeben. Verwenden Sie einen Binder-Parameter, nicht IBinder. Beispiel:

public static class IBinderExampleMultipleAttributes
{
    [FunctionName("CreateBlobInDifferentStorageAccount")]
    public async static Task RunAsync(
            [QueueTrigger("myqueue-items-source-binder2")] string myQueueItem,
            Binder binder,
            ILogger log)
    {
        log.LogInformation($"CreateBlobInDifferentStorageAccount function processed: {myQueueItem}");
        var attributes = new Attribute[]
        {
        new BlobAttribute($"samples-output/{myQueueItem}", FileAccess.Write),
        new StorageAccountAttribute("MyStorageAccount")
        };
        using (var writer = await binder.BindAsync<TextWriter>(attributes))
        {
            await writer.WriteAsync("Hello World!!");
        }
    }
}

Trigger und Bindungen

Die folgende Tabelle zeigt die Bindungen, die in den Hauptversionen der Azure Functions-Runtime unterstützt werden:

type 1.x 2.x und höher1 Trigger Eingabe Output
Blob Storage
Azure Cosmos DB
Dapr3
Event Grid
Event Hubs
HTTP und Webhooks
IoT Hub
Kafka2
Mobile Apps
Notification Hubs
Queue Storage
RabbitMQ2
SendGrid
Service Bus
SignalR
Tabellenspeicherung
Zeitgeber
Twilio

1 Ab Version 2.x der Runtime müssen alle Bindungen mit Ausnahme von HTTP und Timer registriert werden. Siehe Registrieren von Bindungserweiterungen.

2 Trigger werden im Verbrauchstarif nicht unterstützt. Erfordert runtimegesteuerte Trigger.

3 Wird nur in Kubernetes, IoT Edge und anderen selbstgehosteten Modi unterstützt.

Nächste Schritte