Handleiding voor het uitvoeren van C# Azure Functions in een geïsoleerd proces

Dit artikel is een inleiding tot het gebruik van C# voor het ontwikkelen van geïsoleerde .NET-procesfuncties die niet meer worden verwerkt in Azure Functions. Als u niet meer aan het proces werkt, kunt u uw functiecode loskoppelen van Azure Functions runtime. Geïsoleerde proces-C#-functies worden uitgevoerd op zowel .NET 5.0 als .NET 6.0. In-process C#-klassebibliotheekfuncties worden niet ondersteund op .NET 5.0.

Aan de slag Concepten Voorbeelden

Waarom een geïsoleerd .NET-proces?

Voorheen Azure Functions alleen een nauw geïntegreerde modus ondersteund voor .NET-functies, die worden uitgevoerd als een klassebibliotheek in hetzelfde proces als de host. Deze modus biedt een diepe integratie tussen het hostproces en de functies. .NET-klassebibliotheekfuncties kunnen bijvoorbeeld binding-API's en -typen delen. Voor deze integratie is echter ook een nauwe koppeling tussen het hostproces en de .NET-functie vereist. .NET-functies die in-process worden uitgevoerd, moeten bijvoorbeeld worden uitgevoerd op dezelfde versie van .NET als de Functions-runtime. Als u buiten deze beperkingen wilt uitvoeren, kunt u er nu voor kiezen om uit te voeren in een geïsoleerd proces. Met deze procesisolatie kunt u ook functies ontwikkelen die gebruikmaken van huidige .NET-releases (zoals .NET 5.0), die niet systeemeigen worden ondersteund door de Functions-runtime. Zowel geïsoleerde proces- als in-process C#-klassebibliotheekfuncties worden uitgevoerd op .NET 6.0. Zie Ondersteunde versies voor meer informatie.

Omdat deze functies in een afzonderlijk proces worden uitgevoerd, zijn er enkele functie- en functionaliteitsverschillen tussen geïsoleerde .NET-functie-apps en .NET-klassebibliotheekfunctie-apps.

Voordelen van een bijna geen proces meer

Wanneer er geen gebruik meer wordt gemaakt van het proces, kunnen uw .NET-functies profiteren van de volgende voordelen:

  • Minder conflicten: omdat de functies in een afzonderlijk proces worden uitgevoerd, conflicteren de in uw app gebruikte assemblies niet met een andere versie van dezelfde assemblies die door het hostproces worden gebruikt.
  • Volledige controle over het proces: u kunt het starten van de app bepalen en de gebruikte configuraties en de gestarte middleware controleren.
  • Afhankelijkheidsinjectie: omdat u volledige controle over het proces hebt, kunt u het huidige .NET-gedrag gebruiken voor afhankelijkheidsinjectie en middleware opnemen in uw functie-app.

Ondersteunde versies

Versies van de Functions-runtime werken met specifieke versies van .NET. Zie overzicht van runtime-versies voor meer Azure Functions over Functions-versies. Versieondersteuning is afhankelijk van of uw functies worden uitgevoerd in-process of out-of-process (geïsoleerd).

In de volgende tabel ziet u het hoogste niveau van .NET Core of .NET Framework kunnen worden gebruikt met een specifieke versie van Functions.

Versie van Functions-runtime In-process
(.NET-klassebibliotheek)
Out-of-process
(.NET Isolated)
Functions 4.x .NET 6.0 .NET 6.0
Functions 3.x .NET Core 3.1 .NET 5.01
Functions 2.x .NET Core 2.12 n.v.t.
Functions 1.x .NET Framework 4.8 n.v.t.

1 Voor het buildproces is ook .NET Core 3.1 SDK vereist.
2 Zie Overwegingen voor Functions v2.x voor meer informatie.

Voor het laatste nieuws over Azure Functions releases, waaronder het verwijderen van specifieke oudere secundaire versies, controleert u de Azure App Service aankondigingen.

Geïsoleerd .NET-project

Een geïsoleerd .NET-functieproject is in feite een .NET-console-app-project dat gericht is op een ondersteunde .NET-runtime. Hier volgen de basisbestanden die vereist zijn in een geïsoleerd .NET-project:

Pakketverwijzingen

Wanneer uw .NET-project niet meer is verwerkt, wordt een unieke set pakketten gebruikt, die zowel kernfunctionaliteit als bindingsextensies implementeren.

Kernpakketten

De volgende pakketten zijn vereist om uw .NET-functies in een geïsoleerd proces uit te voeren:

Extensiepakketten

Omdat functies die worden uitgevoerd in een geïsoleerd .NET-proces verschillende bindingstypen gebruiken, hebben ze een unieke set bindingsextensiepakketten nodig.

U vindt deze extensiepakketten onder Microsoft.Azure.Functions.Worker.Extensions.

Starten en configureren

Wanneer u geïsoleerde .NET-functies gebruikt, hebt u toegang tot het starten van uw functie-app, meestal in Program.cs. U bent verantwoordelijk voor het maken en starten van uw eigen host-exemplaar. Daarom hebt u ook directe toegang tot de configuratiepijplijn voor uw app. Wanneer u niet meer aan het proces bent, kunt u veel gemakkelijker configuraties toevoegen, afhankelijkheden injecteren en uw eigen middleware uitvoeren.

De volgende code toont een voorbeeld van een [HostBuilder-pijplijn:]

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureServices(s =>
    {
        s.AddSingleton<IHttpResponderService, DefaultHttpResponderService>();
    })
    .Build();

Voor deze code is using Microsoft.Extensions.DependencyInjection; vereist.

Een [HostBuilder wordt] gebruikt om een volledig geitialiseerd [IHost-exemplaar] te bouwen en te retourneren, dat u asynchroon kunt uitvoeren om uw functie-app te starten.

await host.RunAsync();

Configuratie

De [methode ConfigureFunctionsWorkerDefaults] wordt gebruikt om de instellingen toe te voegen die nodig zijn om de functie-app out-of-process te laten uitvoeren. Deze bevat de volgende functionaliteit:

  • Standaardset converters.
  • Stel de [standaard JsonSerializerOptions] in om casing voor eigenschapsnamen te negeren.
  • Integreren met Azure Functions logboekregistratie.
  • Middleware en functies voor uitvoerbinding.
  • Middleware voor functie-uitvoering.
  • Standaard gRPC-ondersteuning.
.ConfigureFunctionsWorkerDefaults()

Als u toegang hebt tot de host builder-pijplijn, kunt u ook app-specifieke configuraties instellen tijdens de initialisatie. U kunt de methode ConfigureAppConfiguration op HostBuilder een of meer keren aanroepen om de configuraties toe te voegen die vereist zijn voor uw functie-app. Zie Configuratie in ASP.NET Core voor meer informatie over app-configuratie.

Deze configuraties zijn van toepassing op uw functie-app die in een afzonderlijk proces wordt uitgevoerd. Als u wijzigingen wilt aanbrengen in de functiehost of trigger- en bindingsconfiguratie, moet u nog steeds het host.json-bestand gebruiken.

Afhankelijkheidsinjectie

Afhankelijkheidsinjectie is vereenvoudigd, vergeleken met .NET-klassebibliotheken. In plaats van dat u een opstartklasse moet maken om services te registreren, moet u [alleen ConfigureServices] aanroepen op de hostbouwer en de extensiemethoden op IServiceCollection gebruiken om specifieke services te injecteren.

In het volgende voorbeeld wordt een singleton-serviceafhankelijkheid injecteert:

.ConfigureServices(s =>
{
    s.AddSingleton<IHttpResponderService, DefaultHttpResponderService>();
})

Voor deze code is using Microsoft.Extensions.DependencyInjection; vereist. Zie Afhankelijkheidsinjectie in ASP.NET Core voor meer ASP.NET Core.

Middleware

.NET Isolated ondersteunt ook middleware-registratie, opnieuw met behulp van een model dat vergelijkbaar is met wat er in ASP.NET. Dit model biedt u de mogelijkheid om logica in de aanroeppijplijn te injecteren en voordat en nadat functies worden uitgevoerd.

De [extensiemethode ConfigureFunctionsWorkerDefaults] heeft een overbelasting waarmee u uw eigen middleware kunt registreren, zoals u in het volgende voorbeeld kunt zien.

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults(workerApplication =>
    {
        // Register our custom middleware with the worker
        workerApplication.UseMiddleware<MyCustomMiddleware>();
    })
    .Build();

Zie het referentievoorbeeld voor aangepaste middleware voor een vollediger voorbeeld van het gebruik van aangepaste middleware in uw functie-app.

Context voor uitvoering

.NET Isolated geeft een [FunctionContext-object] door aan uw functiemethoden. Met dit object kunt u een [ILogger-exemplaar] naar de logboeken laten schrijven door de [GetLogger-methode] aan te roepen en een tekenreeks op te categoryName leveren. Zie Logboekregistratie voor meer informatie.

Bindingen

Bindingen worden gedefinieerd met behulp van kenmerken voor methoden, parameters en retourtypen. Een functiemethode is een methode waarbij een kenmerk en een triggerkenmerk worden toegepast op een Function invoerparameter, zoals wordt weergegeven in het volgende voorbeeld:

[Function("QueueFunction")]
[QueueOutput("output-queue")]
public static string[] Run([QueueTrigger("input-queue")] Book myQueueItem,

    FunctionContext context)

Het triggerkenmerk geeft het triggertype op en verbindt invoergegevens met een methodeparameter. De vorige voorbeeldfunctie wordt geactiveerd door een wachtrijbericht en het wachtrijbericht wordt doorgegeven aan de methode in de myQueueItem parameter .

Het Function kenmerk markeert de methode als een functie-ingangspunt. De naam moet uniek zijn binnen een project, beginnen met een letter en mag alleen letters, cijfers en , met een lengte van _ - maximaal 127 tekens bevatten. Project maken vaak een methode met de naam , maar de naam van de methode Run kan elke geldige C#-methodenaam zijn.

Omdat geïsoleerde .NET-projecten worden uitgevoerd in een afzonderlijk werkproces, kunnen bindingen niet profiteren van uitgebreide bindingsklassen, ICollector<T> zoals IAsyncCollector<T> , en CloudBlockBlob . Er is ook geen directe ondersteuning voor typen die zijn overgenomen van onderliggende service-SDK's, zoals DocumentClient en [BrokeredMessage.] Bindingen zijn in plaats daarvan afhankelijk van tekenreeksen, matrices en serializeerbare typen, zoals gewone oude klasseobjecten (POCO's).

Voor HTTP-triggers moet u HttpRequestData en HttpResponseData gebruiken om toegang te krijgen tot de aanvraag- en antwoordgegevens. Dit komt doordat u geen toegang hebt tot de oorspronkelijke HTTP-aanvraag- en antwoordobjecten wanneer het proces niet meer is uitgevoerd.

Zie het referentievoorbeeld voor bindingsextensies voor een volledige set referentievoorbeelden voor het gebruik van triggers en bindingenbij het uitvoeren van out-of-process.

Invoerbindingen

Een functie kan nul of meer invoerbindingen hebben die gegevens kunnen doorgeven aan een functie. Net als triggers worden invoerbindingen gedefinieerd door een bindingskenmerk toe te passen op een invoerparameter. Wanneer de functie wordt uitgevoerd, probeert de runtime gegevens op te halen die zijn opgegeven in de binding. De gegevens die worden aangevraagd, zijn vaak afhankelijk van informatie die door de trigger wordt verstrekt met behulp van bindingsparameters.

Uitvoerbindingen

Als u naar een uitvoerbinding wilt schrijven, moet u een uitvoerbindingskenmerk toepassen op de functiemethode, die heeft gedefinieerd hoe naar de gebonden service moet worden geschreven. De waarde die door de methode wordt geretourneerd, wordt naar de uitvoerbinding geschreven. In het volgende voorbeeld wordt bijvoorbeeld een tekenreekswaarde naar een berichtenwachtrij met de naam schrijft myqueue-output met behulp van een uitvoerbinding:

[Function("QueueFunction")]
[QueueOutput("output-queue")]
public static string[] Run([QueueTrigger("input-queue")] Book myQueueItem,

    FunctionContext context)
{
    // Use a string array to return more than one message.
    string[] messages = {
        $"Book name = {myQueueItem.Name}",
        $"Book ID = {myQueueItem.Id}"};
    var logger = context.GetLogger("QueueFunction");
    logger.LogInformation($"{messages[0]},{messages[1]}");

    // Queue Output messages
    return messages;
}

Meerdere uitvoerbindingen

De gegevens die naar een uitvoerbinding worden geschreven, zijn altijd de retourwaarde van de functie. Als u naar meer dan één uitvoerbinding wilt schrijven, moet u een aangepast retourtype maken. Voor dit retourtype moet het kenmerk uitvoerbinding worden toegepast op een of meer eigenschappen van de klasse. Het volgende voorbeeld van een HTTP-trigger schrijft naar zowel het HTTP-antwoord als een wachtrijuitvoerbinding:

public static class MultiOutput
{
    [Function("MultiOutput")]
    public static MyOutputType Run([HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequestData req,
        FunctionContext context)
    {
        var response = req.CreateResponse(HttpStatusCode.OK);
        response.WriteString("Success!");

        string myQueueOutput = "some output";

        return new MyOutputType()
        {
            Name = myQueueOutput,
            HttpResponse = response
        };
    }
}

public class MyOutputType
{
    [QueueOutput("myQueue")]
    public string Name { get; set; }

    public HttpResponseData HttpResponse { get; set; }
}

Het antwoord van een HTTP-trigger wordt altijd beschouwd als een uitvoer, dus een retourwaardekenmerk is niet vereist.

HTTP-trigger

HTTP-triggers vertaalt het binnenkomende HTTP-aanvraagbericht naar een [HttpRequestData-object] dat wordt doorgegeven aan de functie. Dit object biedt gegevens van de aanvraag, waaronder Headers , , , en Cookies Identities URL optioneel een bericht Body . Dit object is een weergave van het HTTP-aanvraagobject en niet van de aanvraag zelf.

Op dezelfde manier retourneert de functie een [HttpResponseData-object,] dat gegevens levert die worden gebruikt om het HTTP-antwoord te maken, waaronder het bericht , en optioneel StatusCode een bericht Headers Body .

De volgende code is een HTTP-trigger

[Function("HttpFunction")]
public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequestData req,
    FunctionContext executionContext)
{
    var logger = executionContext.GetLogger("HttpFunction");
    logger.LogInformation("message logged");

    var response = req.CreateResponse(HttpStatusCode.OK);
    response.Headers.Add("Date", "Mon, 18 Jul 2016 16:06:00 GMT");
    response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
    
    response.WriteString("Welcome to .NET 5!!");

    return response;
}

Logboekregistratie

In .NET Isolated kunt u naar logboeken schrijven met behulp van een [ILogger-exemplaar] dat is verkregen van een [FunctionContext-object] dat is doorgegeven aan uw functie. Roep de [GetLogger-methode] aan, waarbij een tekenreekswaarde wordt door gegeven die de naam is van de categorie waarin de logboeken zijn geschreven. De categorie is doorgaans de naam van de specifieke functie van waaruit de logboeken worden geschreven. Zie het bewakingsartikel voor meer informatie over categorieën.

In het volgende voorbeeld ziet u hoe u een [ILogger op kunt halen en] logboeken kunt schrijven binnen een functie:

var logger = executionContext.GetLogger("HttpFunction");
logger.LogInformation("message logged");

Gebruik verschillende methoden van [ILogger om] verschillende logboekniveaus te schrijven, zoals LogWarning of LogError . Zie het bewakingsartikel voor meer informatie over logboekniveaus.

Er [wordt ook een ILogger] opgegeven wanneer afhankelijkheidsinjectie wordt gebruikt.

Verschillen met .NET-klassebibliotheekfuncties

In deze sectie wordt de huidige status beschreven van de functionele en gedragsverschillen die buiten het proces worden uitgevoerd in vergelijking met .NET-klassebibliotheekfuncties die in-process worden uitgevoerd:

Functie/gedrag In-process Out-of-process
.NET-versies .NET Core 3.1
.NET 6.0
.NET 5.0
.NET 6.0
Kernpakketten Microsoft .NET.Sdk.Functions Microsoft.Azure.Functions.Worker
Microsoft.Azure.Functions.Worker.Sdk
Bindingsextensiepakketten Microsoft.Azure.WebJobs.Extensions.* Onder Microsoft.Azure.Functions.Worker.Extensions.*
Logboekregistratie [ILogger doorgegeven] aan de functie ILogger verkregen van FunctionContext
Annuleringstokens Ondersteund Niet ondersteund
Uitvoerbindingen Out-parameters Retourwaarden
Typen uitvoerbindingen IAsyncCollector, [DocumentClient,] BrokeredMessageen andere clientspecifieke typen Eenvoudige typen, JSON-serializeerbare typen en matrices.
Meerdere uitvoerbindingen Ondersteund Ondersteund
HTTP-trigger HttpRequest / ObjectResult HttpRequestData / HttpResponseData
Durable Functions Ondersteund Niet ondersteund
Imperatieve bindingen Ondersteund Niet ondersteund
function.json-artefact Gegenereerd Niet gegenereerd
Configuratie host.json host.json en aangepaste initialisatie
Afhankelijkheidsinjectie Ondersteund Ondersteund
Middleware Niet ondersteund Ondersteund
Koude starttijden Typische Langer, vanwege Just-In-Time-start-up. Voer uit op Linux in plaats Windows mogelijke vertragingen te verminderen.
ReadyToRun Ondersteund TBD

Volgende stappen