Condividi tramite


Guida per l'esecuzione di Azure Functions C# nel modello di lavoro isolato

Questo articolo illustra l'uso di Azure Functions in .NET usando il modello di lavoro isolato. Questo modello consente di gestire versioni specifiche di .NET indipendentemente dagli altri componenti di runtime. Per informazioni sulle versioni di .NET specifiche supportate, vedere versione supportata.

Usare i collegamenti seguenti per iniziare a creare funzioni modello di lavoro isolato .NET immediatamente.

Iniziare Concetti Esempi

Per informazioni sulla distribuzione di un progetto con modello di lavoro isolato in Azure, vedere Distribuire in Azure Functions.

Vantaggi del modello di lavoro isolato

È possibile eseguire le funzioni della libreria di classi di .NET in due modalità: nello stesso processo del runtime dell'host di Funzioni (in-process) o in un processo di lavoro isolato. Quando le funzioni .NET vengono eseguite in un processo di lavoro isolato, è possibile sfruttare i vantaggi seguenti:

  • Meno conflitti: poiché le funzioni vengono eseguite in un processo separato, gli assembly usati nell'app non sono in conflitto con versioni diverse degli stessi assembly usati dal processo host.
  • Controllo completo del processo: si controlla l'avvio dell'app, il che significa che è possibile gestire le configurazioni usate e il middleware avviato.
  • Iniezione di dipendenze standard: Poiché si ha il controllo completo del processo, è possibile usare i comportamenti correnti di .NET per l'inserimento delle dipendenze e incorporare il middleware nell'app per le funzioni.
  • Flessibilità delle versioni .NET: L'esecuzione all'esterno del processo host implica che le tue funzioni possono essere eseguite su versioni di .NET non supportate nativamente dal runtime delle Funzioni, incluso il .NET Framework.

Se si dispone di un'app per le funzioni C# esistente che viene eseguita In-Process, è necessario eseguire la migrazione dell'app per sfruttare questi vantaggi. Per altre informazioni, vedere Migrate .NET app dal modello in-process al modello di lavoro isolato.

Per un confronto completo tra le due modalità, vedere Differenze tra funzioni .NET Azure con processo di lavoro in-process e isolate worker.

Versioni supportate

Le versioni del runtime di Funzioni supportano versioni specifiche di .NET. Per ulteriori informazioni sulle versioni di Funzioni, vedere la panoramica delle versioni di runtime di Azure Functions. Il supporto della versione dipende anche dal fatto che le funzioni eseguono il processo di lavoro In-Process o isolato.

Note

Per informazioni su come modificare la versione del runtime di Funzioni usata dall'app per le funzioni, vedere visualizzare e aggiornare la versione di runtime corrente.

La tabella seguente illustra il livello più elevato di .NET o .NET Framework che può essere usato con una versione specifica di Funzioni.

Versione di runtime di Funzioni Modello di lavoro isolato Modello In-Process34
Funzioni 4.x1 .NET 105
.NET 9.0
.NET 8.0
.NET Framework 4.82
.NET 8.0
Funzioni 1.x3 n/d .NET Framework 4.8

1 .NET 6 è stato precedentemente supportato in entrambi i modelli, ma ha raggiunto il end del supporto ufficiale il 12 novembre 2024. .NET 7 è stato precedentemente supportato nel modello a lavoratore isolato, ma ha raggiunto la fine del supporto ufficiale il 14 maggio 2024.

2 Il processo di compilazione richiede anche .NET SDK.

3 il supporto termina per la versione 1.x del runtime di Azure Functions il 14 settembre 2026. Per altre informazioni, vedere questo annuncio di supporto. Per la prosecuzione del supporto completo, eseguire la migrazione delle app alla versione 4.x.

4 Il supporto per il modello In-Process terminerà il 10 novembre 2026. Per altre informazioni, vedere questo annuncio di supporto. Per la prosecuzione del supporto completo, eseguire la migrazione delle app al modello di lavoro isolato.

5 Non è possibile eseguire .NET 10 app in Linux nel piano a consumo. Per l'esecuzione in Linux, è consigliabile usare invece il piano Flex Consumption. Per istruzioni dettagliate sulla migrazione, vedere Eseguire la migrazione delle app del piano a consumo al piano Flex Consumption.

Per le ultime notizie sulle versioni di Azure Functions, inclusa la rimozione di versioni secondarie meno recenti specifiche, monitorare gli annunci di Azure App Service.

Struttura del progetto

Un progetto .NET per Azure Functions che usa il modello di lavoro isolato è fondamentalmente un progetto console .NET destinato a un runtime di .NET supportato. I seguenti file sono quelli di base richiesti in qualsiasi progetto .NET isolato.

  • File di progetto C# (.csproj) che definisce il progetto e le dipendenze.
  • File program.cs che rappresenta il punto di ingresso per l'app.
  • Tutti i file di codice che definiscono le funzioni.
  • host.json file che definisce la configurazione condivisa dalle funzioni nel project.
  • local.settings.json file che definisce le variabili di ambiente usate dal project quando viene eseguito localmente nel computer.

Per esempi completi, vedere il progetto di esempio .NET 8 e il progetto di esempio .NET Framework 4.8.

Riferimenti ai pacchetti

Un .NET project per Azure Functions che usa il modello di lavoro isolato usa un set univoco di pacchetti per le funzionalità di base e le estensioni di associazione.

Pacchetti principali

Per eseguire le funzioni di .NET in un processo di lavoro isolato, sono necessari i pacchetti seguenti:

Le versioni minime di questi pacchetti dipendono dalla versione di .NET di destinazione:

.NET versione Microsoft.Azure.Functions.Worker Microsoft.Azure.Functions.Worker.Sdk
.NET 10 2.50.0 o versione successiva 2.0.5 o versione successiva
.NET 9 2.0.0 o versione successiva 2.0.0 o versione successiva
.NET 8 1.16.0 o versione successiva 1.11.0 o versione successiva
.NET Framework 1.16.0 o versione successiva 1.11.0 o versione successiva

Versione 2.x

Le versioni 2.x dei pacchetti principali modificano i framework supportati e supportano le nuove API .NET da queste versioni successive. Quando si esegue l'aggiornamento alle versioni 2.x, prendere nota delle modifiche seguenti:

  • A partire dalla versione 2.0.0 di Microsoft. Azure. Functions.Worker.Sdk:
  • A partire dalla versione 2.0.0 di Microsoft. Azure. Functions.Worker:
    • Questa versione aggiunge il supporto per IHostApplicationBuilder. Alcuni esempi in questa guida includono schede per mostrare le alternative che usano IHostApplicationBuilder. Questi esempi richiedono le versioni 2.x.
    • La convalida dell'ambito del provider di servizi è inclusa per impostazione predefinita se viene eseguita in un ambiente di sviluppo. Questo comportamento corrisponde ASP.NET Core.
    • L'opzione EnableUserCodeException è abilitata per impostazione predefinita. La proprietà è ora contrassegnata come obsoleta.
    • L'opzione IncludeEmptyEntriesInMessagePayload è abilitata per impostazione predefinita. Con questa opzione abilitata, i payload del trigger che rappresentano le raccolte includono sempre voci vuote. Ad esempio, se un messaggio viene inviato senza un corpo, è ancora presente un'entrata vuota in string[] per i dati del trigger. L'inclusione di voci vuote facilita il riferimento incrociato con matrici di metadati a cui può fare riferimento anche la funzione. È possibile disabilitare questo comportamento impostando IncludeEmptyEntriesInMessagePayload su false nella configurazione del servizio WorkerOptions.
    • La classe ILoggerExtensions viene rinominata come FunctionsLoggerExtensions. La ridenominazione impedisce un errore di chiamata ambigua quando si usa LogMetric() in un'istanza di ILogger.
    • Per le app che usano HttpResponseData, il WriteAsJsonAsync() metodo non imposta più il codice di stato su 200 OK. In 1.x questo comportamento sovradeda altri codici di errore impostati.
  • Le versioni 2.x interrompono il supporto per .NET 5 TFM.

Pacchetti di estensione

Poiché .NET funzioni di processo di lavoro isolate usano tipi di associazione diversi, richiedono un set univoco di pacchetti di estensione di associazione.

Questi pacchetti di estensione sono disponibili in Microsoft. Azure. Functions.Worker.Extensions.

Avvio e configurazione

Quando si usa il modello di lavoro isolato, hai accesso all'avvio della funzione app, in genere in Program.cs. Si è responsabili della creazione e dell'avvio della propria istanza host. Di conseguenza, hai anche accesso diretto alla pipeline di configurazione per la tua app. Con .NET processo di lavoro isolato di Funzioni, è possibile aggiungere con maggiore facilità configurazioni, inserire dipendenze ed eseguire il proprio middleware.

Per usare IHostApplicationBuilder, l'app deve usare la versione 2.x o successive dei pacchetti principali.

Il codice seguente mostra un esempio di pipeline IHostApplicationBuilder :

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = FunctionsApplication.CreateBuilder(args);

builder.Services
    .AddApplicationInsightsTelemetryWorkerService()
    .ConfigureFunctionsApplicationInsights();

builder.Logging.Services.Configure<LoggerFilterOptions>(options =>
    {
        // The Application Insights SDK adds a default logging filter that instructs ILogger to capture only Warning and more severe logs. Application Insights requires an explicit override.
        // Log levels can also be configured using appsettings.json. For more information, see https://learn.microsoft.com/azure/azure-monitor/app/worker-service#ilogger-logs
        LoggerFilterRule? defaultRule = options.Rules.FirstOrDefault(rule => rule.ProviderName
            == "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider");
        if (defaultRule is not null)
        {
            options.Rules.Remove(defaultRule);
        }
    });

var host = builder.Build();

Prima di chiamare Build() su IHostApplicationBuilder, è necessario:

  • Se si vuole usare ASP.NET Core integration, chiamare builder.ConfigureFunctionsWebApplication().
  • Se si sta scrivendo l'applicazione usando F#, potrebbe essere necessario registrare alcune estensioni di associazione. Vedere la documentazione di installazione per l'estensione Blobs, l'estensione Tables e l'estensione db Cosmos db quando si prevede di usare queste estensioni in un'app F#.
  • Configurare tutti i servizi o la configurazione delle app necessaria al progetto. Per informazioni dettagliate, vedere Configurazione.
  • Se si prevede di usare Application Insights, è necessario chiamare AddApplicationInsightsTelemetryWorkerService() e ConfigureFunctionsApplicationInsights() rispetto alla proprietà Services del generatore. Per informazioni dettagliate, vedere Application Insights.

Se il progetto è destinato al .NET Framework 4.8, è necessario aggiungere anche FunctionsDebugger.Enable(); prima di creare il HostBuilder. Deve essere la prima riga del metodo Main(). Per altre informazioni, vedere Debugging quando la destinazione è .NET Framework.

IHostApplicationBuilder viene usato per compilare e restituire un'istanza IHost completamente inizializzata, eseguita in modo asincrono per avviare l'app per le funzioni.

await host.RunAsync();

Configurazione

Il tipo di generatore usato determina la modalità di configurazione dell'applicazione.

Usare il metodo FunctionsApplication.CreateBuilder() per aggiungere le impostazioni necessarie per l'esecuzione della function app. Il metodo include le funzionalità seguenti:

  • Set predefinito di convertitori.
  • Impostare l'opzione JsonSerializerOptions predefinita per ignorare la differenza fra maiuscole e minuscole nei nomi delle proprietà.
  • Integrare con il logging di Azure Functions.
  • Middleware e funzionalità di binding di output.
  • Middleware di esecuzione della funzione.
  • Supporto gRPC predefinito.
  • Applicare altre impostazioni predefinite da Host.CreateDefaultBuilder().

Hai accesso alla pipeline del builder, in modo da poter impostare qualsiasi configurazione specifica dell'app durante l'inizializzazione. È possibile chiamare metodi di estensione nella proprietà del generatore Configuration per aggiungere eventuali origini di configurazione richieste dal codice. Per altre informazioni sulle app configuration, vedere Configuration in ASP.NET Core.

Queste configurazioni si applicano solo al codice di lavoro creato. Non influiscono direttamente sulla configurazione dell'host o dei trigger e delle associazioni di Funzioni. Per apportare modifiche alla configurazione dell'host o del trigger e dell'associazione delle funzioni, usare il filehost.json.

Note

Non è possibile usare origini di configurazione personalizzate per la configurazione di trigger e associazioni. La configurazione trigger e binding deve essere disponibile per la piattaforma Funzioni e non solo per il codice dell'applicazione. È possibile fornire questa configurazione tramite le impostazioni dell'applicazione, riferimenti a Key Vault o riferimenti a App Configuration.

Inserimento delle dipendenze

Il modello di lavoro isolato usa meccanismi di .NET standard per l'inserimento di servizi.

Quando si usa un IHostApplicationBuilder, utilizzare la relativa proprietà Services per accedere alla IServiceCollection. Nell'esempio seguente viene inserita una dipendenza del servizio singleton:

builder.Services.AddSingleton<IHttpResponderService, DefaultHttpResponderService>();

Questo codice richiede using Microsoft.Extensions.DependencyInjection;. Per altre informazioni, vedere Dependency injection in ASP.NET Core.

Registrare i client di Azure

Usare l'iniezione delle dipendenze per interagire con altri servizi di Azure. È possibile inserire i client dall'SDK Azure per .NET usando il Microsoft.Extensions.Azurepacchetto . Dopo aver installato il pacchetto, registra i client chiamando AddAzureClients() sulla collezione di servizi in Program.cs. L'esempio seguente configura un client named per i BLOB Azure:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.Azure;
using Microsoft.Extensions.Hosting;

var builder = FunctionsApplication.CreateBuilder(args);

builder.Services
    .AddAzureClients(clientBuilder =>
        {
            clientBuilder.AddBlobServiceClient(builder.Configuration.GetSection("MyStorageConnection"))
                .WithName("copierOutputBlob");
        });

builder.Build().Run();

L'esempio seguente illustra come usare questa registrazione e tipi SDK per copiare il contenuto del blob come flusso da un contenitore a un altro utilizzando un client iniettato:

using Microsoft.Extensions.Azure;
using Microsoft.Extensions.Logging;

namespace MyFunctionApp
{
    public class BlobCopier
    {
        private readonly ILogger<BlobCopier> _logger;
        private readonly BlobContainerClient _copyContainerClient;

        public BlobCopier(ILogger<BlobCopier> logger, IAzureClientFactory<BlobServiceClient> blobClientFactory)
        {
            _logger = logger;
            _copyContainerClient = blobClientFactory.CreateClient("copierOutputBlob").GetBlobContainerClient("samples-workitems-copy");
            _copyContainerClient.CreateIfNotExists();
        }

        [Function("BlobCopier")]
        public async Task Run([BlobTrigger("samples-workitems/{name}", Connection = "MyStorageConnection")] Stream myBlob, string name)
        {
            await _copyContainerClient.UploadBlobAsync(name, myBlob);
            _logger.LogInformation($"Blob {name} copied!");
        }

    }
}

In questo esempio, ILogger<T> viene ottenuto anche tramite l'iniezione delle dipendenze, quindi viene registrato automaticamente. Per altre informazioni sulle opzioni di configurazione per la registrazione, vedere Registrazione.

Suggerimento

Nell'esempio viene usata una stringa letterale per il nome del client sia in che nella Program.cs funzione . Prendere invece in considerazione l'uso di una stringa costante condivisa definita nella classe della funzione. Ad esempio, è possibile aggiungere public const string CopyStorageClientName = nameof(_copyContainerClient); e quindi fare riferimento a BlobCopier.CopyStorageClientName in entrambe le posizioni. È possibile definire in modo analogo il nome della sezione di configurazione con la funzione anziché in Program.cs.

Middleware

Il modello di lavoro isolato supporta anche la registrazione del middleware usando un modello simile a quello presente in ASP.NET. Questo modello offre la possibilità di inserire la logica nella pipeline di chiamata, prima e dopo l'esecuzione delle funzioni.

Il metodo di estensione ConfigureFunctionsWorkerDefaults include un overload che consente di registrare il proprio middleware, come illustrato nell'esempio seguente.

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = FunctionsApplication.CreateBuilder(args);

// Register our custom middlewares with the worker
builder
    .UseMiddleware<ExceptionHandlingMiddleware>()
    .UseMiddleware<MyCustomMiddleware>()
    .UseWhen<StampHttpHeaderMiddleware>((context) =>
    {
        // We want to use this middleware only for http trigger invocations.
        return context.FunctionDefinition.InputBindings.Values
                        .First(a => a.Type.EndsWith("Trigger")).Type == "httpTrigger";
    });

builder.Build().Run();

Il UseWhen metodo di estensione registra un middleware che viene eseguito in modo condizionale. È necessario passare un predicato che restituisce un valore booleano a questo metodo. Il middleware partecipa alla pipeline di elaborazione delle chiamate di invocazione quando il predicato restituisce true.

I metodi di estensione seguenti in FunctionContext semplificano l'uso del middleware nel modello isolato.

Metodo Descrizione
GetHttpRequestDataAsync Ottiene l'istanza HttpRequestData quando viene chiamata da un trigger HTTP. Questo metodo restituisce un'istanza di ValueTask<HttpRequestData?>, utile quando si desidera leggere i dati dei messaggi, ad esempio le intestazioni della richiesta e i cookie.
GetHttpResponseData Ottiene l'istanza HttpResponseData quando viene chiamata da un trigger HTTP.
GetInvocationResult Ottiene un'istanza di InvocationResult, che rappresenta il risultato dell'esecuzione della funzione corrente. Utilizzare la proprietà Value per ottenere o impostare il valore in base alle esigenze.
GetOutputBindings Ottiene le voci di binding dell’output per l'esecuzione della funzione corrente. Ogni voce del risultato di questo metodo è di tipo OutputBindingData. È possibile utilizzare la proprietà Value per ottenere o impostare il valore in base alle esigenze.
BindInputAsync Associa un elemento di binding di input per l'istanza BindingMetadata richiesta. Ad esempio, usa questo metodo quando hai una funzione con un binding BlobInput di input che richiede l'uso del middleware.

Questo esempio mostra un'implementazione middleware che legge l'istanza HttpRequestData e aggiorna l'istanza durante l'esecuzione HttpResponseData della funzione:

internal sealed class StampHttpHeaderMiddleware : IFunctionsWorkerMiddleware
{
    public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
    {
        var requestData = await context.GetHttpRequestDataAsync();

        string correlationId;
        if (requestData!.Headers.TryGetValues("x-correlationId", out var values))
        {
            correlationId = values.First();
        }
        else
        {
            correlationId = Guid.NewGuid().ToString();
        }

        await next(context);

        context.GetHttpResponseData()?.Headers.Add("x-correlationId", correlationId);
    }
}

Questo middleware verifica la presenza di un'intestazione di richiesta specifica (x-correlationId). Quando l'intestazione è presente, il middleware usa il valore dell'intestazione per contrassegnare un'intestazione di risposta. In caso contrario, genera un nuovo valore GUID e usa tale valore per contrassegnare l'intestazione della risposta.

Suggerimento

Il modello mostrato in precedenza per impostare le intestazioni di risposta dopo await next(context) potrebbe non funzionare in modo affidabile in tutti gli scenari. Questo problema è particolarmente vero quando si usa l'integrazione ASP.NET Core o in determinate configurazioni di runtime in cui il flusso di risposta potrebbe essere già stato inviato. Per assicurarsi che le intestazioni siano impostate correttamente, è consigliabile recuperare la risposta da context.GetInvocationResult().Value e impostare le intestazioni prima che la risposta venga restituita dalla funzione, invece di tentare di modificarle nel middleware al termine dell'esecuzione della funzione.

Per un esempio più completo dell'uso del middleware personalizzato nella tua app di funzioni, vedi l'esempio di riferimento del middleware personalizzato .

Personalizzazione della serializzazione JSON

Il modello di lavoro isolato usa System.Text.Json per impostazione predefinita. È possibile personalizzare il comportamento del serializzatore configurando i servizi come parte del file Program.cs. Questa sezione illustra la serializzazione generica e non influisce sulla serializzazione JSON trigger HTTP con integrazione ASP.NET Core, che è necessario configurare separatamente.

using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = FunctionsApplication.CreateBuilder(args);

builder.ConfigureFunctionsWebApplication();

builder.Services.Configure<JsonSerializerOptions>(jsonSerializerOptions =>
    {
        jsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
        jsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
        jsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;

        // override the default value
        jsonSerializerOptions.PropertyNameCaseInsensitive = false;
    });

builder.Build().Run();

Per usare JSON.NET (Newtonsoft.Json) per la serializzazione, installare il pacchetto Microsoft.Azure.Core.NewtonsoftJson. Quindi, nella registrazione del servizio, riassegna la Serializer proprietà nella WorkerOptions configurazione. L'esempio seguente illustra questa configurazione usando ConfigureFunctionsWebApplication, ma funziona anche per ConfigureFunctionsWorkerDefaults:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = FunctionsApplication.CreateBuilder(args);

builder.ConfigureFunctionsWebApplication();

builder.Services.Configure<WorkerOptions>(workerOptions =>
    {
        var settings = NewtonsoftJsonObjectSerializer.CreateJsonSerializerSettings();
        settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        settings.NullValueHandling = NullValueHandling.Ignore;

        workerOptions.Serializer = new NewtonsoftJsonObjectSerializer(settings);
    });

builder.Build().Run();

Metodi riconosciuti come funzioni

Un metodo della funzione è un metodo pubblico di una classe pubblica con un attributo Function applicato al metodo e un attributo trigger applicato a un parametro di input, come illustrato nell'esempio seguente:

[Function(nameof(QueueInputOutputFunction))]
[QueueOutput("output-queue")]
public string[] QueueInputOutputFunction([QueueTrigger("input-queue")] Album myQueueItem, FunctionContext context)

L'attributo trigger specifica il tipo di trigger e associa i dati di input a un parametro del metodo. La funzione di esempio precedente viene attivata da un messaggio della coda e il messaggio della coda viene passato al metodo nel myQueueItem parametro .

L'attributo Function indica il metodo come punto di ingresso della funzione. Il nome deve essere univoco all'interno di un project, iniziare con una lettera e contenere solo lettere, numeri, _ e -, fino a 127 caratteri di lunghezza. Project modelli spesso creano un metodo denominato Run, ma il nome del metodo può essere qualsiasi nome di metodo C# valido. Il metodo deve essere un membro pubblico di una classe pubblica. In genere deve essere un metodo di istanza, in modo che i servizi possano essere passati tramite inserimento delle dipendenze.

Parametri di funzione

Ecco alcuni dei parametri che è possibile includere all’interno di una firma del metodo di funzione:

Contesto di esecuzione

Nel modello di lavoro isolato il processo di lavoro passa un oggetto FunctionContext ai metodi della funzione. Questo oggetto consente di ottenere un'istanza di ILogger per scrivere nei log chiamando il metodo GetLogger e fornendo una stringa categoryName. È possibile usare questo contesto per ottenere ILogger senza dover usare l'inserimento delle dipendenze. Per altre informazioni, vedere Logging.

Token di annullamento

Una funzione può accettare un parametro cancellationToken , che consente al sistema operativo di notificare al codice quando la funzione sta per essere terminata. È possibile usare questa notifica per assicurarsi che la funzione non termini in modo imprevisto lasciando i dati in uno stato incoerente.

Le funzioni .NET eseguite in un processo di lavoro isolato supportano i token di annullamento. L'esempio seguente genera un'eccezione quando viene ricevuta una richiesta di annullamento:

[Function(nameof(ThrowOnCancellation))]
public async Task ThrowOnCancellation(
    [EventHubTrigger("sample-workitem-1", Connection = "EventHubConnection")] string[] messages,
    FunctionContext context,
    CancellationToken cancellationToken)
{
    _logger.LogInformation("C# EventHub {functionName} trigger function processing a request.", nameof(ThrowOnCancellation));

    foreach (var message in messages)
    {
        cancellationToken.ThrowIfCancellationRequested();
        await Task.Delay(6000); // task delay to simulate message processing
        _logger.LogInformation("Message '{msg}' was processed.", message);
    }
}

Nell'esempio seguente vengono eseguite azioni di pulizia quando viene ricevuta una richiesta di annullamento:

[Function(nameof(HandleCancellationCleanup))]
public async Task HandleCancellationCleanup(
    [EventHubTrigger("sample-workitem-2", Connection = "EventHubConnection")] string[] messages,
    FunctionContext context,
    CancellationToken cancellationToken)
{
    _logger.LogInformation("C# EventHub {functionName} trigger function processing a request.", nameof(HandleCancellationCleanup));

    foreach (var message in messages)
    {
        if (cancellationToken.IsCancellationRequested)
        {
            _logger.LogInformation("A cancellation token was received, taking precautionary actions.");
            // Take precautions like noting how far along you are with processing the batch
            _logger.LogInformation("Precautionary activities complete.");
            break;
        }

        await Task.Delay(6000); // task delay to simulate message processing
        _logger.LogInformation("Message '{msg}' was processed.", message);
    }
}

Scenari che comportano l'annullamento

Il token di annullamento viene segnalato quando la chiamata alla funzione viene annullata. Diversi motivi possono causare un annullamento e questi motivi variano a seconda del tipo di trigger usato. Alcuni motivi comuni sono:

  • Disconnessione client: il client che richiama la funzione si disconnette. Questo motivo è molto probabile per le funzioni trigger HTTP.
  • Riavvio dell'app per le funzioni: tu o la piattaforma riavviate (o arrestate) l'app per le funzioni nello stesso momento in cui è richiesta un'invocazione. Un riavvio può verificarsi a causa di spostamenti di istanze di lavoro, aggiornamenti delle istanze di lavoro o scalabilità.

Considerazioni sull'annullamento

  • Le chiamate in corso durante un evento di riavvio potrebbero essere ritentate a seconda del modo in cui sono state attivate. Per altre informazioni, vedere la documentazione sui tentativi di ripetizione.

  • L'host invia l'invocazione al processo di lavoro anche nel caso in cui il token di annullamento venga annullato prima che l'host riesca a inviare la richiesta di invocazione al processo di lavoro.

  • Se non si desidera che le chiamate annullate vengano inviate al worker, aggiungere la proprietà SendCanceledInvocationsToWorker al file host.json per disabilitare questo comportamento.

    Questo esempio mostra un host.json file che usa questa proprietà:

    {
        "version": "2.0",
        "SendCanceledInvocationsToWorker": "false"
    }
    
  • L'impostazione di SendCanceledInvocationsToWorker su false potrebbe causare un'eccezione FunctionInvocationCanceled con il log seguente:

    L'annullamento è stato richiesto. La richiesta di invocazione con ID '{invocationId}' è annullata e non verrà inviata al lavoratore.

    Questa eccezione si verifica quando il token di cancellazione viene annullato (come risultato di uno degli eventi descritti in precedenza) prima che l'host invii una richiesta di invocazione in ingresso al worker. Questa eccezione può essere ignorata in modo sicuro ed è prevista quando SendCanceledInvocationsToWorker è false.

Programmazione asincrona

Il worker isolato di .NET non imposta un SynchronizationContext personalizzato. Ciò significa che SynchronizationContext.Current è null durante l'esecuzione della funzione. Dopo un await, le continuazioni vengono pianificate nel pool di thread, ovvero il comportamento .NET standard.

Poiché non c'è SynchronizationContext da sopprimere, l'uso di ConfigureAwait(false) nel codice della funzione non ha alcun effetto pratico. Il processo di lavoro isolato viene eseguito come host generico .NET standard (applicazione console), quindi lo stesso comportamento async/await previsto in qualsiasi ASP.NET Core o applicazione console si applica qui. Questo vale anche per le applicazioni di lavoro isolate di .NET Framework (net48), poiché il processo di lavoro è sempre un eseguibile console usando HostBuilder.

Note

Durable Functions gli orchestratori hanno vincoli di threading specifici. Il thread di riproduzione dell'orchestratore deve eseguire le continuazioni, pertanto l'uso di ConfigureAwait(false) nelle funzioni o nel middleware dell'orchestratore può interferire con l'esecuzione dell'orchestrazione. Per altre informazioni, vedere i vincoli di codice Durable Functions.

Collegamenti

Definire le associazioni usando attributi su metodi, parametri e tipi restituiti. Le associazioni possono fornire dati come stringhe, matrici e tipi serializzabili, ad esempio oggetti di classe precedenti (POCO). Per alcune estensioni binding, è possibile anche eseguire il binding a tipi specifici del servizio definiti negli SDK del servizio.

Per i trigger HTTP, vedere la sezione trigger HTTP.

Per un set completo di campioni di riferimento che usano trigger e associazioni a funzioni di processo worker isolato, consulta il campione di riferimento delle estensioni di associazione .

Binding di input

Una funzione può avere zero o più associazioni di input che passano dati alla funzione. Come i trigger, è possibile definire associazioni di input applicando un attributo di associazione a un parametro di input. Quando la funzione viene eseguita, il runtime tenta di ottenere i dati specificati nell'associazione. I dati richiesti spesso dipendono dalle informazioni fornite dal trigger tramite parametri di associazione.

Binding di output

Per scrivere in un'associazione di output, è necessario applicare un attributo di associazione di output al metodo di funzione. Questo attributo definisce come scrivere al servizio associato. Il valore di ritorno del metodo viene scritto nel vincolo di output. Nell’esempio seguente viene scritto un valore stringa in una coda di messaggi denominata output-queue usando un'associazione di output:

[Function(nameof(QueueInputOutputFunction))]
[QueueOutput("output-queue")]
public string[] QueueInputOutputFunction([QueueTrigger("input-queue")] Album myQueueItem, FunctionContext context)
{
    // Use a string array to return more than one message.
    string[] messages = {
        $"Album name = {myQueueItem.Name}",
        $"Album songs = {myQueueItem.Songs}"};

    _logger.LogInformation("{msg1},{msg2}", messages[0], messages[1]);

    // Queue Output messages
    return messages;
}

Associazioni di output multiple

I dati scritti in un'associazione di output sono sempre il valore restituito della funzione. Se è necessario scrivere in più associazioni di output, è necessario creare un tipo restituito personalizzato. Questo tipo restituito deve avere l'attributo di binding di output applicato a una o più proprietà della classe . L'esempio seguente è una funzione attivata da HTTP che usa ASP.NET Core integration e scrive sia nella risposta HTTP che in un vincolo di output della coda.

public class MultipleOutputBindings
{
    private readonly ILogger<MultipleOutputBindings> _logger;

    public MultipleOutputBindings(ILogger<MultipleOutputBindings> logger)
    {
        _logger = logger;
    }

    [Function("MultipleOutputBindings")]
    public MyOutputType Run([HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req)
    {
        _logger.LogInformation("C# HTTP trigger function processed a request.");
        var myObject = new MyOutputType
        {
            Result = new OkObjectResult("C# HTTP trigger function processed a request."),
            MessageText = "some output"
        };
        return myObject;
    }

    public class MyOutputType
    {
        [HttpResult]
        public IActionResult Result { get; set; }

        [QueueOutput("myQueue")]
        public string MessageText { get; set; }
    }
}

Quando si usano tipi restituiti personalizzati per più associazioni di output con integrazione ASP.NET Core, è necessario aggiungere l'attributo [HttpResult] alla proprietà che fornisce il risultato. L'attributo HttpResult è disponibile quando si usa SDK 1.17.3-preview2 o versione successiva insieme a versione 3.2.0 o versione successiva dell'estensione HTTP e version 1.3.0 o versione successiva dell'estensione ASP.NET Core.

Tipi di SDK

Per alcuni tipi di associazione specifici del servizio, è possibile fornire dati di associazione usando tipi di SDK e framework del servizio. Questi tipi offrono funzionalità che vanno oltre quelle di una stringa serializzata o di un semplice vecchio oggetto CLR (POCO) serializzato. Per usare i tipi più recenti, aggiornare il project per usare le versioni più recenti delle dipendenze principali.

Dipendenza Requisito versione
Microsoft. Azure. Functions.Worker 1.18.0 o versione successiva
Microsoft. Azure. Functions.Worker.Sdk 1.13.0 o versione successiva

Quando si testano i tipi di SDK in locale nel computer, è anche necessario usare Azure Functions Core Tools versione 4.0.5000 o successiva. È possibile controllare la versione corrente usando il func --version comando .

Ogni estensione di associazione ha anche un proprio requisito di versione minima, descritto negli articoli di riferimento sull'estensione. Queste estensioni di associazione supportano attualmente i tipi di SDK:

Extension Tipi Livello di supporto
Azure Blob Storage BlobClient
BlobContainerClient
BlockBlobClient
PageBlobClient
AppendBlobClient
Trigger: disponibilità generale
Input: disponibilità generale
Azure Cosmos DB CosmosClient
Database
Container
Input: disponibilità generale
Azure Event Grid CloudEvent
EventGridEvent
Trigger: disponibilità generale
Azure Event Hubs EventData
EventHubProducerClient
Trigger: disponibilità generale
Azure Queue Storage QueueClient
QueueMessage
Trigger: disponibilità generale
Azure Service Bus ServiceBusClient
ServiceBusReceiver
ServiceBusSender
ServiceBusMessage
Trigger: disponibilità generale
Azure Table Storage TableClient
TableEntity
Input: disponibilità generale

Considerazioni per i tipi di SDK:

  • Quando si usano espressioni di associazione che si basano sui dati del trigger, non è possibile usare i tipi SDK per il trigger stesso.
  • Per gli scenari di output in cui è possibile usare un tipo di SDK, creare e usare direttamente i client SDK anziché usare un'associazione di output.
  • Il trigger Azure Cosmos DB usa il feed di modifiche Azure Cosmos DB ed espone gli elementi del feed di modifiche come tipi serializzabili JSON. Di conseguenza, i tipi SDK non sono supportati per questo trigger.

Trigger HTTP

I trigger HTTP consentono di richiamare una funzione da una richiesta HTTP. È possibile usare due approcci diversi:

  • Modello di integrazione ASP.NET Core che usa i concetti noti agli sviluppatori ASP.NET Core
  • Un modello predefinito, che non richiede dipendenze aggiuntive e usa tipi personalizzati per le richieste e le risposte HTTP. Questo approccio viene mantenuto per garantire la compatibilità con le versioni precedenti di .NET app di lavoro isolate.

integrazione di ASP.NET Core

Questa sezione illustra come usare gli oggetti richiesta e risposta HTTP sottostanti usando tipi di ASP.NET Core, tra cui HttpRequest, HttpResponse e IActionResult. Questo modello non è disponibile per apps destinate a .NET Framework, che deve invece usare il modello built-in.

Note

Questo modello non espone tutte le funzionalità di ASP.NET Core. In particolare, non fornisce accesso alle funzionalità di routing e pipeline middleware di ASP.NET Core. L'integrazione con ASP.NET Core richiede l'uso di pacchetti aggiornati.

Per abilitare l'integrazione ASP.NET Core per HTTP:

  1. Aggiungere un riferimento nel progetto al pacchetto Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore, versione 1.0.0 o successiva.

  2. Aggiornare il project per usare queste versioni specifiche del pacchetto:

  3. Nel file Program.cs aggiornare la configurazione del generatore host per chiamare ConfigureFunctionsWebApplication(). Questo metodo sostituisce ConfigureFunctionsWorkerDefaults() qualora si utilizzasse tale metodo altrimenti. L'esempio seguente mostra una configurazione minima senza altre personalizzazioni:

    Note

    L'applicazione deve fare riferimento alla versione 2.0.0 o successiva di Microsoft. Azure. Functions.Worker.Extensions.Http.AspNetCore per usare l'integrazione ASP.NET Core con IHostApplicationBuilder.

    using Microsoft.Azure.Functions.Worker.Builder;
    using Microsoft.Extensions.Hosting;
    
    var builder = FunctionsApplication.CreateBuilder(args);
    
    builder.ConfigureFunctionsWebApplication();    
    
    builder.Build().Run();
    
  4. Aggiornare tutte le funzioni attivate da HTTP esistenti per usare i tipi di ASP.NET Core. Questo esempio mostra HttpRequest e IActionResult standard usati per una semplice funzione "hello, world":

    [Function("HttpFunction")]
    public IActionResult Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get")] HttpRequest req)
    {
        return new OkObjectResult($"Welcome to Azure Functions, {req.Query["name"]}!");
    }
    

Serializzazione JSON con integrazione di ASP.NET Core

ASP.NET Core ha un proprio livello di serializzazione e non viene influenzato dalla personalizzazione della configurazione di serializzazione generale. Per personalizzare il comportamento di serializzazione usato per i trigger HTTP, è necessario includere una chiamata .AddMvc() come parte della registrazione del servizio. Il IMvcBuilder restituito può essere usato per modificare le impostazioni di serializzazione JSON di ASP.NET Core.

È possibile continuare a usare HttpRequestData e HttpResponseData durante l'uso dell'integrazione ASP.NET, anche se per la maggior parte delle app, è preferibile usare HttpRequest e IActionResult. L'uso di HttpRequestData/HttpResponseData non richiama il livello di serializzazione ASP.NET Core e si basa invece sulla configurazione della serializzazione del ruolo di lavoro generale per l'app. Tuttavia, quando ASP.NET Core'integrazione è abilitata, potrebbe essere comunque necessario aggiungere la configurazione. Il comportamento predefinito da ASP.NET Core consiste nell'impedire l'I/O sincrono. Per usare un serializzatore personalizzato che non supporta operazioni di I/O asincrone, ad esempio NewtonsoftJsonObjectSerializer, è necessario abilitare le operazioni di I/O sincrone per l'applicazione KestrelServerOptionsconfigurando .

L'esempio seguente illustra come configurare json.NET (Newtonsoft.Json) e il pacchetto NuGet Microsoft.AspNetCore.Mvc.NewtonsoftJson per la serializzazione usando questo approccio:

using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = FunctionsApplication.CreateBuilder(args);

builder.ConfigureFunctionsWebApplication();

builder.Services
    .AddApplicationInsightsTelemetryWorkerService()
    .ConfigureFunctionsApplicationInsights();

builder.Services.AddMvc().AddNewtonsoftJson();

// Only needed if using HttpRequestData/HttpResponseData and a serializer that doesn't support asynchronous IO
// builder.Services.Configure<KestrelServerOptions>(options => options.AllowSynchronousIO = true);

builder.Build().Run();

Modello HTTP predefinito

Nel modello predefinito, il sistema converte il messaggio di richiesta HTTP in ingresso in un oggetto HttpRequestData che passa alla funzione. Questo oggetto fornisce dati della richiesta, tra cui Headers, Cookies, Identities, URL e facoltativamente un messaggio Body. Questo oggetto rappresenta la richiesta HTTP, ma non è direttamente connessa al listener HTTP sottostante o al messaggio ricevuto.

Importante

Se si usa HttpRequestData, il corpo della richiesta HTTP non può essere un flusso. Ad esempio, se la richiesta ha l'intestazione Transfer-Encoding: chunked e senza intestazione Content-Length, la proprietà HttpRequestData dell'oggetto Body sarà un flusso nullo. Se è necessario usare le richieste HTTP di streaming, è consigliabile usare il modello di integrazione ASP.NET Core.

Analogamente, la funzione restituisce un oggetto HttpResponseData, che fornisce dati usati per creare la risposta HTTP, incluso il messaggio StatusCode, Headers e facoltativamente un messaggio Body.

Nell'esempio seguente viene illustrato l'uso di HttpRequestData e HttpResponseData:

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

    var response = req.CreateResponse(HttpStatusCode.OK);
    response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
    response.WriteString("Welcome to .NET isolated worker !!");

    return response;
}

Registrazione

È possibile scrivere nei log usando un'istanza ILogger<T> o ILogger. È possibile ottenere il logger tramite l'inserimento delle dipendenze di un ILogger<T> oggetto o di un oggetto ILoggerFactory:

public class MyFunction {
    
    private readonly ILogger<MyFunction> _logger;
    
    public MyFunction(ILogger<MyFunction> logger) {
        _logger = logger;
    }
    
    [Function(nameof(MyFunction))]
    public void Run([BlobTrigger("samples-workitems/{name}", Connection = "")] string myBlob, string name)
    {
        _logger.LogInformation($"C# Blob trigger function Processed blob\n Name: {name} \n Data: {myBlob}");
    }

}

Note

Quando si inserisce un oggetto ILogger<T> nel costruttore della classe, come nell'esempio precedente, la categoria di log viene impostata automaticamente sul nome completo di tale classe, ad esempio MyFunctionApp.MyFunction. Questi nomi di categoria contengono . caratteri (punto). Quando si ospita l'app per le funzioni in Linux, non è possibile usare le variabili di ambiente per sostituire i livelli di log per le categorie che contengono periodi. Per ovviare a questa limitazione, è invece possibile configurare i livelli di log nel codice o in un appsettings.json file.

È anche possibile ottenere il logger da un oggetto FunctionContext passato alla tua funzione. Chiamare il metodo GetLogger<T> o GetLogger passando un valore stringa che corrisponde al nome della categoria in cui vengono scritti i log. La categoria è in genere il nome della funzione specifica da cui vengono scritti i log. Per altre informazioni sulle categorie, vedere l'articolo sul monitoraggio.

Usare i metodi di ILogger<T> e ILogger per scrivere vari livelli di log, ad esempio LogWarning o LogError. Per altre informazioni sui livelli di log, vedere l'articolo sul monitoraggio. È possibile personalizzare i livelli di log per i componenti aggiunti al codice registrando i filtri:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

var builder = FunctionsApplication.CreateBuilder(args);

builder.ConfigureFunctionsWebApplication();

// Registers IHttpClientFactory.
// By default this sends a lot of Information-level logs.
builder.Services.AddHttpClient();

// Disable IHttpClientFactory Informational logs.
// Note -- you can also remove the handler that does the logging: https://github.com/aspnet/HttpClientFactory/issues/196#issuecomment-432755765 
builder.Logging.AddFilter("System.Net.Http.HttpClient", LogLevel.Warning);
    
builder.Build().Run();

Come parte della configurazione dell'app in Program.cs, è possibile definire anche il comportamento per cui gli errori vengono visualizzati nei log. Il comportamento predefinito dipende dal tipo di generatore in uso.

Quando si usa un IHostApplicationBuilderoggetto , le eccezioni generate dal codice passano attraverso il sistema senza modifiche. Non sono necessarie altre configurazioni.

Approfondimenti sulle Applicazioni

È possibile configurare l'applicazione del processo isolato per inviare i log direttamente a Application Insights. Questa configurazione sostituisce il comportamento predefinito dell'inoltro dei log tramite l'host. A meno che non si usi Aspire, configurare l'integrazione diretta di Application Insights perché consente di controllare come vengono emessi tali log.

L'integrazione di Application Insights non è abilitata per impostazione predefinita in tutte le esperienze di installazione. Alcuni modelli creano progetti di Funzioni con i pacchetti necessari e il codice di avvio commentati. Per usare l'integrazione di Application Insights, rimuovere il commento da queste righe in Program.cs e il file /project .csproj. Le istruzioni nella parte restante di questa sezione descrivono anche come abilitare l'integrazione.

Se il project fa parte di un'orchestrazione Aspire, usa invece OpenTelemetry per il monitoraggio. Non abilitare l'integrazione diretta di Application Insights all'interno dei progetti Aspira. Configurare invece l'esportatore OpenTelemetry di Azure Monitor come parte del progetto predefinito del servizio. Se il tuo progetto di Funzioni utilizza l'integrazione di Application Insights in un contesto Aspire, l'applicazione presenta errori all'avvio.

Installare i pacchetti

Per scrivere i log direttamente in Application Insights dal codice, aggiungere riferimenti a questi pacchetti nel project:

Eseguire i comandi seguenti per aggiungere questi riferimenti al project:

dotnet add package Microsoft.ApplicationInsights.WorkerService
dotnet add package Microsoft.Azure.Functions.Worker.ApplicationInsights

Configurare l'avvio

Dopo aver installato i pacchetti, chiamare AddApplicationInsightsTelemetryWorkerService() e ConfigureFunctionsApplicationInsights() durante la configurazione del servizio nel Program.cs file, come illustrato nell'esempio seguente:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
    
var builder = FunctionsApplication.CreateBuilder(args);

builder.Services
    .AddApplicationInsightsTelemetryWorkerService()
    .ConfigureFunctionsApplicationInsights();

builder.Build().Run();

La chiamata a ConfigureFunctionsApplicationInsights() aggiunge un oggetto ITelemetryModule che ascolta un evento definito dalla funzione ActivitySource. Questo modulo crea la telemetria delle dipendenze necessaria per supportare il tracciamento distribuito. Per altre informazioni su AddApplicationInsightsTelemetryWorkerService() e su come usarlo, vedere Application Insights for Worker Service applications.

Gestire i livelli di log

Importante

L'host Funzioni e il worker del processo isolato hanno configurazioni separate per i livelli di log. Qualsiasi configurazione di Application Insights in host.json non influisce sulla registrazione dal ruolo di lavoro e, analogamente, la configurazione nel codice del ruolo di lavoro non influisce sulla registrazione dall'host. Applicare le modifiche in entrambe le posizioni se lo scenario richiede la personalizzazione in entrambi i livelli.

Il resto dell'applicazione continua a funzionare con ILogger e ILogger<T>. Tuttavia, per impostazione predefinita, l'SDK Application Insights aggiunge un filtro di registrazione che indica al logger di acquisire solo avvisi e log più gravi. È possibile configurare i livelli di log nel processo di lavoro isolato in uno dei modi seguenti:

Metodo di configurazione Vantaggi
Nel tuo codice Promuove una separazione più chiara tra configurazioni lato host e lato lavoro.
Utilizzo di appsettings.json Utile quando si desidera impostare livelli di log diversi per categorie diverse senza dover modificare il codice.

Per disabilitare il comportamento predefinito e acquisire tutti i livelli di log, rimuovere la regola di filtro come parte della configurazione del servizio:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

var builder = FunctionsApplication.CreateBuilder(args);

builder.Services
    .AddApplicationInsightsTelemetryWorkerService()
    .ConfigureFunctionsApplicationInsights();

builder.Logging.Services.Configure<LoggerFilterOptions>(options =>
    {
        LoggerFilterRule? defaultRule = options.Rules.FirstOrDefault(rule => rule.ProviderName
            == "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider");
        if (defaultRule is not null)
        {
            options.Rules.Remove(defaultRule);
        }
    });

builder.Build().Run();

Per altre informazioni sulla configurazione della registrazione, vedere Logging in .NET e Application Insights per applicazioni del servizio di lavoro.

Prestazioni e ottimizzazioni

Questa sezione illustra le opzioni che è possibile abilitare per migliorare le prestazioni relative all'avvio a freddo.

In generale, l'app deve usare le versioni più recenti delle relative dipendenze principali. Aggiornare almeno il project come indicato di seguito:

  1. Aggiornare Microsoft. Azure. Functions.Worker alla versione 1.19.0 o successiva.
  2. Aggiornare Microsoft. Azure. Functions.Worker.Sdk alla versione 1.16.4 o successiva.
  3. Aggiungi un riferimento al framework specifico Microsoft.AspNetCore.App, a meno che l'app non sia destinata a .NET Framework.

Il frammento di codice seguente illustra questa configurazione nel contesto di un file project:

  <ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.21.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.16.4" />
  </ItemGroup>

Segnaposto

I segnaposto sono una funzionalità della piattaforma che migliora l'avvio a freddo delle app indirizzate a .NET 6 o versioni successive. Per usare questa ottimizzazione, è necessario abilitare in modo esplicito i segnaposto seguendo questa procedura:

  1. Aggiorna la configurazione del progetto per usare le versioni delle dipendenze più recenti, come descritto nella sezione precedente.

  2. Impostare l'impostazione dell'applicazione WEBSITE_USE_PLACEHOLDER_DOTNETISOLATED su 1. Utilizzare questo comando az functionapp config appsettings set:

    az functionapp config appsettings set -g <groupName> -n <appName> --settings 'WEBSITE_USE_PLACEHOLDER_DOTNETISOLATED=1'
    

    In questo esempio sostituire <groupName> con il nome del gruppo di risorse e sostituire <appName> con il nome dell'app per le funzioni.

  3. Assicurarsi che la proprietà netFrameworkVersion dell'app per le funzioni corrisponda al framework di destinazione del project, che deve essere .NET 6 o versione successiva. Usare questo comando az functionapp config set:

    az functionapp config set -g <groupName> -n <appName> --net-framework-version <framework>
    

    In questo esempio sostituire anche <framework> con la stringa di versione appropriata, ad esempio v8.0, in base alla versione del .NET di destinazione.

  4. Assicurarsi che l'app per le funzioni sia configurata per l'uso di un processo a 64 bit. Usare questo comando az functionapp config set:

    az functionapp config set -g <groupName> -n <appName> --use-32bit-worker-process false
    

Importante

Quando si imposta il parametro WEBSITE_USE_PLACEHOLDER_DOTNETISOLATED su 1, è necessario impostare correttamente tutte le altre configurazioni delle applicazioni di funzione. In caso contrario, l'app per le funzioni potrebbe non essere avviata.

Executor ottimizzato

L'executor della funzione è un componente della piattaforma che provoca l'esecuzione delle chiamate. Una versione ottimizzata di questo componente è abilitata per impostazione predefinita a partire dalla versione 1.16.2 dell'SDK. Non sono necessarie altre configurazioni.

ReadyToRun

È possibile compilare l'app per le funzioni come file binari ReadyToRun. ReadyToRun è una forma di compilazione anticipata che consente di migliorare le prestazioni di avvio per ridurre l'effetto degli avvii a freddo durante l'esecuzione in un piano a consumo. ReadyToRun è disponibile in .NET 6 e versioni successive e richiede versione 4.0 o versioni successive del runtime di Azure Functions.

ReadyToRun richiede la compilazione del progetto contro l'architettura dell'ambiente di esecuzione dell'app di hosting. Quando queste architetture non sono allineate, l'app rileva un errore all'avvio. Selezionare l'identificatore di runtime da questa tabella:

Sistema operativo L'app è a 32 bit1 Identificatore di runtime
Windows True win-x86
Windows False win-x64
Linux True N/D (non supportato)
Linux False linux-x64

1 Solo le app a 64 bit sono idonee per altre ottimizzazioni delle prestazioni.

Per verificare se il Windows app è a 32 bit o a 64 bit, eseguire il comando dell'interfaccia della riga di comando seguente, sostituendo <group_name> con il nome del gruppo di risorse e <app_name> con il nome dell'applicazione. Un output "true" indica che l'app è a 32 bit e "false" indica 64 bit.

 az functionapp config show -g <group_name> -n <app_name> --query "use32BitWorkerProcess"

È possibile modificare l'applicazione impostando 64 bit con il comando seguente, usando le stesse sostituzioni:

az functionapp config set -g <group_name> -n <app_name> --use-32bit-worker-process false`

Per compilare il project come ReadyToRun, aggiornare il file di project aggiungendo gli elementi <PublishReadyToRun> e <RuntimeIdentifier>. L'esempio seguente illustra una configurazione per la pubblicazione in un'app per le funzioni a 64 bit di Windows.

<PropertyGroup>
  <TargetFramework>net8.0</TargetFramework>
  <AzureFunctionsVersion>v4</AzureFunctionsVersion>
  <RuntimeIdentifier>win-x64</RuntimeIdentifier>
  <PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>

Se non si desidera impostare l'<RuntimeIdentifier> come parte del file di project, è anche possibile configurare questa impostazione come parte del movimento di pubblicazione stesso. Ad esempio, in un'applicazione per funzioni Windows a 64 bit, il comando CLI di .NET è:

dotnet publish --runtime win-x64

In Visual Studio impostare l'opzione Target Runtime nel profilo di pubblicazione sull'identificatore di runtime corretto. Se impostato sul valore predefinito di Portabile, ReadyToRun non viene usato.

Eseguire la distribuzione in Azure Functions

Quando si distribuisce il codice del progetto delle funzioni in Azure, deve essere eseguito in un'app per le funzioni o in un contenitore Linux. È necessario creare l'app per le funzioni e altre risorse necessarie Azure prima di distribuire il codice.

È possibile distribuire l'app per le funzioni anche in un contenitore Linux. Per altre informazioni, vedere Lavorare con i container e le funzioni di Azure.

Creare risorse Azure

È possibile creare l'app per le funzioni e altre risorse necessarie in Azure usando uno di questi metodi:

  • Visual Studio: Visual Studio può creare risorse durante il processo di pubblicazione del codice.
  • Visual Studio Code: Visual Studio Code può connettersi alla sottoscrizione, creare le risorse necessarie per l'app e quindi pubblicare il codice.
  • Azure CLI: usare il Azure CLI per creare le risorse necessarie in Azure.
  • Azure PowerShell: usare Azure PowerShell per creare le risorse necessarie in Azure.
  • Deployment templates: usare i modelli arm e i file Bicep per automatizzare la distribuzione delle risorse necessarie per Azure. Assicurarsi che il modello includa le impostazioni necessarie.
  • Azure portal: creare le risorse necessarie nel Azure portal.

Pubblicare l'applicazione

Dopo aver creato l'app per le funzioni e altre risorse necessarie in Azure, distribuire il codice progetto in Azure usando uno di questi metodi:

Per altre informazioni, vedere Deployment technologies in Azure Functions.

Payload della distribuzione

Molti dei metodi di distribuzione usano un archivio ZIP. Se si crea manualmente l'archivio ZIP, deve seguire la struttura descritta in questa sezione. In caso contrario, l'app potrebbe riscontrare errori all'avvio.

Il payload della distribuzione deve corrispondere all'output di un comando dotnet publish, anche se senza la cartella padre che lo contiene. L'archivio ZIP deve essere creato dai file seguenti:

  • .azurefunctions/
  • extensions.json
  • functions.metadata
  • host.json
  • worker.config.json
  • Il file eseguibile del tuo progetto (un'app console)
  • Altri file di supporto e directory con peering a tale eseguibile

Il processo di compilazione genera questi file e non è consigliabile modificarli direttamente.

Suggerimento

È possibile usare il func pack comando in Core Tools per generare correttamente un archivio ZIP per la distribuzione. Il supporto per func pack è attualmente disponibile in anteprima.

Quando si prepara un archivio ZIP per la distribuzione, comprimere solo il contenuto della directory di output, non la directory di inclusione stessa. Quando l'archivio viene estratto nella directory di lavoro corrente, i file elencati in precedenza devono essere immediatamente visibili.

Requisiti di distribuzione

Per eseguire .NET funzioni nel modello di lavoro isolato in Azure, è necessario soddisfare alcuni requisiti. I requisiti dipendono dal sistema operativo:

Quando si crea l'app per le funzioni in Azure usando i metodi nella sezione precedente, queste impostazioni necessarie vengono aggiunte automaticamente. Quando si creano queste risorse usando i modelli ARM o i file Bicep per l'automazione, è necessario assicurarsi di impostarli nel modello.

Aspire

Aspire è uno stack tecnologico con scelte predefinite che semplifica lo sviluppo di applicazioni distribuite nel cloud. È possibile integrare progetti di modelli di lavoratore isolati nelle orchestrazioni di Aspire 13. Per altre informazioni, vedere Azure Functions with Aspira.

Debug

Quando si esegue localmente usando Visual Studio o Visual Studio Code, è possibile eseguire il debug del progetto di lavoro isolato .NET come di consueto. Esistono tuttavia due scenari di debug che non funzionano come previsto.

Debug remoto con Visual Studio

Poiché l'app del processo di lavoro isolato viene eseguita all'esterno del runtime Funzioni, è necessario collegare il debugger remoto a un processo separato. Per altre informazioni sul debug con Visual Studio, vedere Debug remoto.

Debug quando la destinazione è .NET Framework

Se il progetto isolato ha come destinazione .NET Framework 4.8, è necessario eseguire dei passaggi manuali per abilitare il debugging. Questi passaggi non sono necessari se si usa un altro framework di destinazione.

L'app deve iniziare con una chiamata a FunctionsDebugger.Enable(); come prima operazione. Ciò si verifica nel metodo Main() prima di inizializzare un HostBuilder. Il file Program.cs dovrebbe essere simile al seguente:

using System;
using System.Diagnostics;
using Microsoft.Extensions.Hosting;
using Microsoft.Azure.Functions.Worker;
using NetFxWorker;

namespace MyDotnetFrameworkProject
{
    internal class Program
    {
        static void Main(string[] args)
        {
            FunctionsDebugger.Enable();

            var host = FunctionsApplication
                .CreateBuilder(args)
                .Build();

            host.Run();
        }
    }
}

Successivamente, è necessario collegarsi manualmente al processo usando un debugger di .NET Framework. Visual Studio non esegue ancora automaticamente questa operazione per le applicazioni .NET Framework con processo worker isolato e l'operazione "Avvia il debug" dovrebbe essere evitata.

Nella directory del progetto (o nella relativa directory di output di compilazione) esegui:

func host start --dotnet-isolated-debug

Viene avviato il ruolo di lavoro e il processo viene arrestato con il messaggio seguente:

Azure Functions .NET Worker (PID: <process id>) initialized in debug mode. Waiting for debugger to attach...

Dove <process id> è l'ID del processo di lavoro. È ora possibile usare Visual Studio per collegarsi manualmente al processo. Per istruzioni su questa operazione, vedere Come collegarsi a un processo in esecuzione.

Dopo aver collegato il debugger, l'esecuzione del processo riprende e sarà possibile eseguire il debug.

Anteprima .NET versioni

Prima di una versione disponibile a livello generale, una versione .NET potrebbe essere rilasciata in uno stato Preview o Go-live. Per informazioni dettagliate su questi stati, vedere i criteri ufficiali di supporto .NET.

Anche se potrebbe essere possibile impostare come destinazione una determinata versione da un project di Funzioni locale, le app per le funzioni ospitate in Azure potrebbero non avere tale versione disponibile. Azure Functions può essere usato solo con le versioni di anteprima o go live indicate in questa sezione.

Azure Functions non funziona attualmente con le versioni ".NET Anteprima" o "Go-live". Vedere Versioni supportate per avere un elenco delle versioni disponibili a livello generale che è possibile usare.

Uso di una versione di anteprima del .NET SDK

Per usare Azure Functions con una versione di anteprima di .NET, è necessario aggiornare il project in base a:

  1. Installazione della versione .NET SDK pertinente nello sviluppo
  2. Modifica dell'impostazione TargetFramework nel file .csproj

Quando si esegue la distribuzione nell'app per le funzioni in Azure, è anche necessario assicurarsi che il framework sia reso disponibile per l'app. Durante il periodo di anteprima, alcuni strumenti ed esperienze potrebbero non mostrare la nuova versione di anteprima come opzione. Se non viene visualizzata la versione di anteprima inclusa nel Azure portal, ad esempio, è possibile usare l'API REST, i file Bicep o il Azure CLI per configurare la versione manualmente.

Per le app ospitate in Windows, usare il comando Azure CLI seguente. Sostituire <groupName> con il nome del gruppo di risorse e sostituire <appName> con il nome dell'app per le funzioni. Sostituire <framework> con la stringa di versione appropriata, ad esempio v8.0.

az functionapp config set -g <groupName> -n <appName> --net-framework-version <framework>

Considerazioni sull'uso delle versioni di anteprima di .NET

Tenere presenti queste considerazioni quando si usano Funzioni con versioni di anteprima di .NET:

  • Quando si creano le funzioni in Visual Studio, è necessario usare Visual Studio Insider, che supporta la compilazione di progetti Azure Functions con SDK di anteprima .NET.

  • Assicurarsi di avere gli strumenti e i modelli di Funzioni più recenti. Per aggiornare gli strumenti:

    1. Passare a Strumenti>Opzioni, scegliere Azure Functions sotto Progetti e Soluzioni>Altre Impostazioni.
    2. Selezionare Controlla aggiornamenti e installare gli aggiornamenti come richiesto.
  • Durante un periodo di anteprima, l'ambiente di sviluppo potrebbe avere una versione più recente dell'anteprima .NET rispetto al servizio ospitato. Ciò può causare l'esito negativo dell'app per le funzioni durante la distribuzione. Per risolvere questo problema, è possibile specificare la versione dell'SDK da usare in global.json.

    1. Eseguire il comando dotnet --list-sdks e prendere nota della versione di anteprima attualmente in uso durante lo sviluppo locale.
    2. Eseguire il comando dotnet new globaljson --sdk-version <SDK_VERSION> --force, dove <SDK_VERSION> è la versione in uso in locale. Ad esempio, dotnet new globaljson --sdk-version dotnet-sdk-10.0.100-preview.5.25277.114 --force fa sì che il sistema usi l'SDK di .NET 10 Preview 5 durante la compilazione del project.

Note

A causa del caricamento JIT dei framework di anteprima, le app per le funzioni in esecuzione su Windows possono riscontrare tempi di avvio a freddo maggiori rispetto alle versioni in disponibilità generale precedenti.

Passaggi successivi