Freigeben über


Entwickeln von C#-Klassenbibliotheksfunktionen mithilfe von Azure Functions

Wichtig

Die Unterstützung für das In-Process-Modell endet am 10. November 2026. Es wird dringend empfohlen, Ihre Apps zum isolierten Workermodell zu migrieren, um den vollständigen Support zu ermöglichen.

Dieser Artikel ist eine Einführung in die Entwicklung von Azure Functions durch Verwenden von C# in .NET-Klassenbibliotheken. Diese Klassenbibliotheken werden zur In-Process-Ausführung mit der Functions-Laufzeitumgebung verwendet. Ihre .NET-Funktionen können alternativ _isolated aus der Funktionen-Laufzeit ausführen, die mehrere Vorteile bietet. Weitere Informationen finden Sie im isolierten Workermodell. Einen umfassenden Vergleich zwischen diesen beiden Modellen finden Sie unter Unterschiede zwischen dem isolierten Workermodell und dem In-Process-Modell.

Wichtig

Dieser Artikel unterstützt Funktionen der .NET-Klassenbibliothek, die prozessintern mit der Runtime ausgeführt werden. Ihre C#-Funktionen können auch außerhalb des Prozesses ausgeführt und von der Functions-Runtime isoliert werden. Das isolierte Workerprozessmodell ist die einzige Möglichkeit, Nicht-LTS-Versionen von .NET- und .NET Framework-Apps in aktuellen Versionen der Functions-Runtime auszuführen. Weitere Informationen finden Sie unter isolierte .NET-Workerprozessfunktionen. Einen umfassenden Vergleich zwischen .NET-Funktionen in isolierten Workerprozessen und prozessinternen .NET-Funktionen finden Sie unter Unterschiede zwischen prozessinternen .NET-Azure-Funktionen und .NET-Azure-Funktionen in isolierten Workerprozessen.

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 unterstützen bestimmte Versionen von .NET. Weitere Informationen zu den Functions-Versionen finden Sie unter Übersicht über die Runtimeversionen von Azure Functions. Die Versionsunterstützung hängt auch davon ab, ob Ihre Funktionen prozessintern oder in einem isolierten Workerprozess ausgeführt werden.

Hinweis

Informationen zum Ändern der von Ihrer Funktions-App verwendeten Functions-Runtimeversion finden Sie unter Anzeigen und Aktualisieren der aktuellen Runtimeversion.

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

Version der Functions-Laufzeit Isoliertes Workermodell Prozessinternes Modell5
Functions 4.x1 .NET 9.0 (Vorschauversion)
.NET 8.0
.NET 6.02
.NET Framework 4.83
.NET 8.0
.NET 6.02
Functions 1.x4 .NET Framework 4.8

1 .NET 7 wurde zuvor beim isolierten Workermodell unterstützt, hat aber am 14. Mai 2024 das Ende der offiziellen Unterstützung erreicht.

2 .NET 6 wird ab dem 12. November 2024 nicht mehr offiziell unterstützt.

3 Für den Buildprozess ist auch das .NET SDK erforderlich.

4 Der Support für die Version 1.x der Azure Functions-Runtime endet am 14. September 2026. Weitere Informationen finden Sie in dieser Supportankündigung. Um weiterhin uneingeschränkten Support zu erhalten, müssen Sie Ihre Apps zur Version  4.x migrieren.

5 Die Unterstützung für das In-Process-Modell endet am 10. November 2026. Weitere Informationen finden Sie in dieser Supportankündigung. Um weiterhin uneingeschränkten Support zu erhalten, müssen Sie Ihre Apps zum Modell mit isolierten Workern migrieren.

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

Aktualisieren, um .NET 8 zu verwenden

Apps, die das In-Process-Modell verwenden, können .NET 8 als Ziel verwenden, indem die in diesem Abschnitt beschriebenen Schritte ausgeführt werden. Wenn Sie sich jedoch für diese Option entscheiden, sollten Sie dennoch mit der Planung Ihrer Migration zum isolierten Workermodell beginnen, bevor die Unterstützung für das In-Process-Modell am 10. November 2026 endet.

Viele Apps können die Konfiguration der Funktions-App in Azure ändern, ohne dass Code aktualisiert oder erneut bereitgestellt werden muss. Zum Ausführen von .NET 8 mit dem In-Process-Modell sind drei Konfigurationen erforderlich:

  • Die Anwendungseinstellung FUNCTIONS_WORKER_RUNTIME muss auf den Wert „dotnet“ festgelegt werden.
  • Die Anwendungseinstellung FUNCTIONS_EXTENSION_VERSION muss mit dem Wert „~4“ festgelegt werden.
  • Die Anwendungseinstellung FUNCTIONS_INPROC_NET8_ENABLED muss mit dem Wert „1“ festgelegt werden.
  • Sie müssen die Stapelkonfiguration aktualisieren, um auf .NET 8 zu verweisen.

Die Unterstützung für .NET 8 verwendet weiterhin Version 4.x der Functions-Runtime, und es ist keine Änderung an der konfigurierten Laufzeitversion erforderlich.

Um Ihr lokales Projekt zu aktualisieren, stellen Sie zunächst sicher, dass Sie die neuesten Versionen lokaler Tools verwenden. Stellen Sie dann sicher, dass das Projekt auf Version 4.4.0 oder höher von Microsoft.NET.Sdk.Functions verweist. Anschließend können Sie TargetFramework in „net8.0“ ändern. Sie müssen zudem local.settings.json aktualisieren, um den auf „dotnet“ festgelegten FUNCTIONS_WORKER_RUNTIME-Wert und den auf „1“ festgelegten FUNCTIONS_INPROC_NET8_ENABLED-Wert aufzunehmen.

Im Folgenden sehen Sie ein Beispiel für eine minimale project-Datei mit diesen Änderungen:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.4.0" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

Im Folgenden sehen Sie ein Beispiel für eine minimale local.settings.json-Datei mit diesen Änderungen:

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_INPROC_NET8_ENABLED": "1",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet"
    }
}

Wenn Ihre App Microsoft.Azure.DurableTask.Netherite.AzureFunctions verwendet, stellen Sie sicher, dass sie auf Version 1.5.3 oder höher ausgerichtet ist. Aufgrund eines Behavior Change in .NET 8 lösen Apps mit älteren Versionen des Pakets eine mehrdeutige Konstruktorausnahme aus.

Möglicherweise müssen Sie andere Änderungen an Ihrer App basierend auf der Versionsunterstützung ihrer anderen Abhängigkeiten vornehmen.

Version 4.x der Funktionen-Laufzeit bietet gleichwertige Funktionen für .NET 6 und .NET 8. Das In-Process-Modell enthält keine zusätzlichen Features oder Updates, die in neue .NET 8-Funktionen integriert werden. Die Laufzeit unterstützt z. B. keine Schlüsseldienste. Um die neuesten .NET 8-Funktionen und -Verbesserungen vollständig nutzen zu können, müssen Sie zum isolierten Workermodell migrieren.

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 Methode mit einem 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 Beispiel oben zeigt die Verwendung einer statischen Methode, jedoch sind keine Funktionen erforderlich, damit sie statisch ist.

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:

  • Eingabe- und Ausgabebindungen, die als solche gekennzeichnet werden, indem Sie sie mit Attributen versehen.
  • Ein ILogger- oder TraceWriter-Parameter (ILogger) für die TraceWriter.
  • Ein CancellationToken-Parameter für CancellationToken.
  • Binden von Ausdrücken Parameter zum Abrufen von Metadaten für Trigger.

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 Ausgabebindung oder mehrere Ausgabebindungen 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 Datei function.json wird mit dem NuGet-Paket Microsoft.NET.Sdk.Functions ausgeführt.

Das folgende Beispiel zeigt die relevanten Teile der .csproj Dateien, die über unterschiedliche Zielframeworks in desselben Sdk Paketen verfügen:

<PropertyGroup>
  <TargetFramework>net8.0</TargetFramework>
  <AzureFunctionsVersion>v4</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
  <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.5.0" />
</ItemGroup>

Wichtig

Ab der Version 4.0.6517 von Core Tools müssen In-Process-Modellprojekte mindestens auf die Version 4.5.0 von Microsoft.NET.Sdk.Functions verweisen. Bei Verwendung einer älteren Version tritt bei dem Befehl func start ein Fehler auf.

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 4.x-Auslöser und -Bindungen für .NET Core ausgelegt sind.

Das Sdk-Paket hängt außerdem von Sdk 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 Microsoft.NET.Sdk.Functions 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 4.x ist Core Tools in der Erweiterung Azure Functions und WebJobs-Tools enthalten. Sie können für Functions 1.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 6 und höher verfügbar und setzt Azure Functions Runtimeversion 4.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>net8.0</TargetFramework>
  <AzureFunctionsVersion>v4</AzureFunctionsVersion>
  <PublishReadyToRun>true</PublishReadyToRun>
  <RuntimeIdentifier>win-x86</RuntimeIdentifier>
</PropertyGroup>

Wichtig

Ab .NET 6 wurde Unterstützung für zusammengesetzte ReadyToRun-Kompilierung hinzugefügt. Sehen Sie sich die plattform- und architekturübergreifenden Einschränkungen für ReadyToRun an.

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.

Betrachten Sie den Fall, dass Sie eine Funktion verwenden, die Nachrichten in Batches verarbeitet. Die folgende von Azure Service Bus ausgelöste Funktion verarbeitet ein Array aus ServiceBusReceivedMessage-Objekten, das einen Batch eingehender Nachrichten darstellt, die von einem bestimmten Funktionsaufruf verarbeitet werden sollen:

using Azure.Messaging.ServiceBus;
using System.Threading;

namespace ServiceBusCancellationToken
{
    public static class servicebus
    {
        [FunctionName("servicebus")]
        public static void Run([ServiceBusTrigger("csharpguitar", Connection = "SB_CONN")]
               ServiceBusReceivedMessage[] messages, CancellationToken cancellationToken, ILogger log)
        {
            try
            { 
                foreach (var message in messages)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        log.LogInformation("A cancellation token was received. Taking precautionary actions.");
                        //Take precautions like noting how far along you are with processing the batch
                        log.LogInformation("Precautionary activities --complete--.");
                        break;
                    }
                    else
                    {
                        //business logic as usual
                        log.LogInformation($"Message: {message} was processed.");
                    }
                }
            }
            catch (Exception ex)
            {
                log.LogInformation($"Something unexpected happened: {ex.Message}");
            }
        }
    }
}

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 ILogger. 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 <VERSION> 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 APPINSIGHTS_INSTRUMENTATIONKEY 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.

Testen von Funktionen

In den folgenden Artikeln wird gezeigt, wie Sie eine In-Process-C#-Klassenbibliotheksfunktion zu Testzwecken lokal ausführen:

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 Values. 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:

Typ 1.x1 2.x und höher2 Trigger Eingabe Output
Blob Storage
Azure Cosmos DB
Azure Data Explorer
Azure SQL
Dapr4
Event Grid
Event Hubs
HTTP und Webhooks
IoT Hub
Kafka3
Mobile Apps
Notification Hubs
Queue Storage
Redis
RabbitMQ3
SendGrid
Service Bus
SignalR
Tabellenspeicherung
Zeitgeber
Twilio

Hinweise:

  1. Der Support für Version 1.x der Azure Functions-Laufzeit endet am 14. September 2026. Es wird dringend empfohlen, dass Sie Ihre Apps zu Version 4.x migrieren, um vollständigen Support zu erhalten.
  2. Ab Version 2.x der Runtime müssen alle Bindungen mit Ausnahme von HTTP und Timer registriert werden. Siehe Registrieren von Bindungserweiterungen.
  3. Trigger werden im Plan „Verbrauch“ nicht unterstützt. Erfordert runtimegesteuerte Trigger.
  4. Wird nur in Kubernetes, IoT Edge und anderen selbstgehosteten Modi unterstützt.

Nächste Schritte