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

Questo articolo è un'introduzione all'uso di Funzioni di Azure in .NET, usando il modello di lavoro isolato. Questo modello consente al progetto di scegliere come destinazione le versioni di .NET indipendentemente da altri componenti di runtime. Per informazioni sulle versioni specifiche di .NET supportate, vedere versione supportata.

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

Introduzione Concetti Esempi

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

Vantaggi del modello di lavoro isolato

Esistono due modalità in cui è possibile eseguire le funzioni della libreria di classi .NET: 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.
  • Inserimento di dipendenze standard: poiché si ha il controllo completo del processo, è possibile usare i comportamenti .NET correnti per l'inserimento delle dipendenze e incorporare middleware nell'app per le funzioni.
  • Flessibilità della versione .NET: poiché l’esecuzione avviene al di fuori del processo host, le funzioni possono essere eseguite in versioni di .NET non supportate in modo nativo dal runtime di Funzioni, persino in .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 Eseguire la migrazione di app .NET dal modello In-Process al modello di lavoro isolato.

Per un confronto esaustivo tra le due modalità, vedere Differenze tra il processo di lavoro In-Process e isolato per Funzioni di Azure .NET.

Versioni supportate

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

Nota

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 del runtime di Funzioni Modello di lavoro isolato Modello In-Process5
Funzioni 4.x1 .NET 9.0 (anteprima)
.NET 8.0
.NET 6.02
.NET Framework 4.83
.NET 8.0
.NET 6.02
Funzioni 1.x4 n/d .NET Framework 4.8

1.NET 7 è stato precedentemente supportato nel modello di lavoro isolato, ma ha raggiunto la fine del supporto ufficiale il 14 maggio 2024.

2 .NET 6 raggiunge la fine del supporto ufficiale il 12 novembre 2024.

3 Il processo di compilazione richiede anche .NET SDK.

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

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

Per le ultime notizie sulle versioni di Funzioni di Azure, inclusa la rimozione di versioni secondarie meno recenti specifiche, monitorare gli annunci del servizio app di Azure.

Struttura progetto

Un progetto .NET per Funzioni di Azure che usa il modello di lavoro isolato è fondamentalmente un progetto di app console .NET destinato a un runtime .NET supportato. Di seguito sono riportati i file di base necessari in qualsiasi progetto isolato .NET:

  • File di progetto C# (con estensione 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.
  • File host.json che definisce la configurazione condivisa dalle funzioni del progetto.
  • File local.settings.json che definisce le variabili di ambiente usate dal progetto quando vengono eseguite 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 progetto .NET per Funzioni di Azure che si serve del modello di lavoro isolato usa un set univoco di pacchetti, sia per le funzionalità di base che per le estensioni di associazione.

Pacchetti core

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

Versione 2.x (anteprima)

Le versioni 2.x dei pacchetti principali modificano i framework supportati e supportano le nuove API .NET da queste versioni successive. Quando si usa .NET 9 (anteprima) o versione successiva, l'app deve fare riferimento alla versione 2.0.0-preview1 o successiva di entrambi i pacchetti.

Le versioni di anteprima iniziali sono compatibili con il codice scritto nella versione 1.x. Tuttavia, durante il periodo di anteprima, le versioni più recenti possono introdurre modifiche di comportamento che potrebbero influenzare il codice scritto.

Quando si esegue l'aggiornamento alle versioni 2.x, prendere nota delle modifiche seguenti:

  • A partire dalla versione 2.0.0-preview2, Microsoft.Azure.Functions.Worker.Sdk aggiunge configurazioni predefinite per le compilazioni del contenitore SDK.
  • A partire dalla versione 2.0.0-preview2 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 a 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, per i dati del trigger è ancora presente string[] una voce vuota. L'inclusione di voci vuote facilita il riferimento incrociato con matrici di metadati a cui può anche fare riferimento la funzione. È possibile disabilitare questo comportamento impostando su IncludeEmptyEntriesInMessagePayload false nella configurazione del WorkerOptions servizio.
    • La ILoggerExtensions classe viene rinominata in FunctionsLoggerExtensions. La ridenominazione impedisce un errore di chiamata ambiguo quando si usa LogMetric() in un'istanza ILogger di .

Pacchetti di estensione

Poiché le funzioni del processo di lavoro isolato .NET usano tipi di associazione diversi, richiedono un set univoco di pacchetti di estensione di binding.

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

Avvio e configurazione

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

Il codice seguente illustra un esempio di pipeline HostBuilder:

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureServices(s =>
    {
        s.AddApplicationInsightsTelemetryWorkerService();
        s.ConfigureFunctionsApplicationInsights();
        s.AddSingleton<IHttpResponderService, DefaultHttpResponderService>();
        s.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://video2.skills-academy.com/en-us/azure/azure-monitor/app/worker-service#ilogger-logs
            LoggerFilterRule? toRemove = options.Rules.FirstOrDefault(rule => rule.ProviderName
                == "Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider");

            if (toRemove is not null)
            {
                options.Rules.Remove(toRemove);
            }
        });
    })
    .Build();

Questo codice richiede using Microsoft.Extensions.DependencyInjection;.

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

  • Chiamare ConfigureFunctionsWebApplication() se si usa l’integrazione ASP.NET Core o, in caso contrario, ConfigureFunctionsWorkerDefaults(). Per informazioni dettagliate su queste opzioni, vedere Trigger HTTP.
    Se si scrive l'applicazione usando F#, alcune estensioni di trigger e binding richiedono una configurazione aggiuntiva. Vedere la documentazione sull’installazione per l'estensione BLOB, l'estensione Table e l'estensione Cosmos DB quando si prevede di usare queste estensioni in un'app F#.
  • Configurare i servizi o la configurazione app necessari per il progetto. Per informazioni dettagliate, vedere Configurazione.
    Se si prevede di usare Application Insights, è necessario chiamare AddApplicationInsightsTelemetryWorkerService() e ConfigureFunctionsApplicationInsights() nel delegato ConfigureServices(). Per informazioni dettagliate, vedere Application Insights.

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

HostBuilder 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();

Impostazione

Il tipo di generatore usato determina come configurare l'applicazione.

Il metodo ConfigureFunctionsWorkerDefaults viene usato per aggiungere le impostazioni necessarie per l'esecuzione dell'app per le funzioni. 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à.
  • Eseguire l'integrazione con la registrazione di Funzioni di Azure.
  • Middleware e funzionalità di binding di output.
  • Middleware di esecuzione della funzione.
  • Supporto gRPC predefinito.
.ConfigureFunctionsWorkerDefaults()

Avere accesso alla pipeline del generatore host significa poter impostare qualsiasi configurazione specifica dell'app durante l'inizializzazione. È possibile chiamare il metodo ConfigureAppConfiguration in HostBuilder una o più volte per aggiungere eventuali origini di configurazione richieste dal codice. Per altre informazioni sulla configurazione delle app, vedere Configurazione in ASP.NET Core.

Queste configurazioni si applicano solo al codice di lavoro creato e non influiscono direttamente sulla configurazione dell'host o dei trigger e delle associazioni di Funzioni. Per apportare modifiche all'host delle funzioni o alla configurazione trigger e binding, è comunque necessario usare il file host.json.

Nota

Non è possibile usare origini di configurazione personalizzate per la configurazione di trigger e binding. 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, i riferimenti a Key Vault o le funzionalità di riferimento per la Configurazione app.

Inserimento delle dipendenze

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

Quando si usa , HostBuilderchiamare ConfigureServices nel generatore host e usare i metodi di estensione in IServiceCollection per inserire servizi specifici. Nell'esempio seguente viene inserita una dipendenza del servizio singleton:

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

Questo codice richiede using Microsoft.Extensions.DependencyInjection;. Per altre informazioni, vedere Inserimento delle dipendenze in ASP.NET Core.

Registrare i client di Azure

L'inserimento delle dipendenze può essere usato per interagire con altri servizi di Azure. È possibile inserire client dall’SDK Azure per .NET usando il pacchetto Microsoft.Extensions.Azure. Dopo aver installato il pacchetto, registrare i client chiamando AddAzureClients() nella raccolta di servizi in Program.cs. Nell’esempio seguente viene configurato un client denominato per i BLOB di Azure:

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

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureServices((hostContext, services) =>
    {
        services.AddAzureClients(clientBuilder =>
        {
            clientBuilder.AddBlobServiceClient(hostContext.Configuration.GetSection("MyStorageConnection"))
                .WithName("copierOutputBlob");
        });
    })
    .Build();

host.Run();

L'esempio seguente illustra come usare questa registrazione e i tipi di SDK per copiare il contenuto del BLOB come flusso da un contenitore a un altro usando un client inserito:

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!");
        }

    }
}

ILogger<T> in questo esempio è stato ottenuto anche tramite l'inserimento 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 con valori letterali per il nome del client sia in Program.cs che nella funzione. Considerare invece 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, sempre utilizzando 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.

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults(workerApplication =>
    {
        // Register our custom middlewares with the worker

        workerApplication.UseMiddleware<ExceptionHandlingMiddleware>();

        workerApplication.UseMiddleware<MyCustomMiddleware>();

        workerApplication.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";
        });
    })
    .Build();

Il metodo di estensione UseWhen può essere usato per registrare un middleware che viene eseguito in modo condizionale. È necessario passare a questo metodo un predicato che restituisce un valore booleano, e il middleware partecipa alla pipeline di elaborazione delle chiamate quando il valore restituito del predicato è true.

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

metodo Descrizione
GetHttpRequestDataAsync Esso 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, è possibile usare questo metodo quando si dispone di una funzione con un'associazione di input BlobInput che deve essere usata dal middleware.

Questo è un esempio di implementazione del middleware che legge l'istanza HttpRequestData e aggiorna l'istanza HttpResponseData durante l'esecuzione 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) e, quando presente, usa il valore dell'intestazione per contrassegnare un'intestazione di risposta. In caso contrario, genera un nuovo valore GUID e lo usa per contrassegnare l'intestazione della risposta. Per un esempio più completo dell'uso di middleware personalizzato nell'app per le funzioni, vedere 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 per utilizzo generico e non influisce sulla serializzazione JSON del trigger HTTP con l'integrazione di ASP.NET Core, che deve essere configurata separatamente.

L'esempio seguente illustra l'uso di ConfigureFunctionsWebApplication, ma funziona anche per ConfigureFunctionsWorkerDefaults:

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

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication((IFunctionsWorkerApplicationBuilder builder) =>
    {
        builder.Services.Configure<JsonSerializerOptions>(jsonSerializerOptions =>
        {
            jsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
            jsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
            jsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;

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

host.Run();

È possibile usare invece JSON.NET (Newtonsoft.Json) per la serializzazione. A tale scopo, installare il pacchetto Microsoft.Azure.Core.NewtonsoftJson. Quindi, nella registrazione del servizio, si riassegna la proprietà Serializer nella configurazione WorkerOptions. L'esempio seguente illustra l'uso di ConfigureFunctionsWebApplication, ma funziona anche per ConfigureFunctionsWorkerDefaults:

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

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

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

host.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(QueueFunction))]
[QueueOutput("output-queue")]
public string[] Run([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 parametro myQueueItem.

L'attributo Function indica il metodo come punto di ingresso della funzione. Il nome deve essere univoco all'interno di un progetto, iniziare con una lettera e contenere solo lettere, numeri e caratteri _ e -, fino a 127 caratteri. I modelli di progetto 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

.NET isolato passa un oggetto FunctionContext ai metodi della funzione. Questo oggetto consente di ottenere un'istanza 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 Registrazione.

Token di annullamento

Una funzione può accettare un parametro CancellationToken, che consente al sistema operativo di notificare il 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.

I token di annullamento sono supportati nelle funzioni .NET quando vengono eseguiti in un processo di lavoro isolato. Nell’esempio seguente viene generata un'eccezione alla ricezione di 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 alla ricezione di 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);
    }
}

Bindings

Le associazioni vengono definite 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 esempi di riferimento che usano trigger e associazioni con funzioni di processo di lavoro isolate, vedere l'esempio di riferimento delle estensioni binding.

Associazioni di input

Una funzione può avere zero o più associazioni di input che possono passare dati a una funzione. Come i trigger, le associazioni di input vengono definite applicando un attributo di binding 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 binding.

Associazioni di output

Per scrivere in un'associazione di output, è necessario applicare un attributo di binding di output al metodo della funzione, che definisce come scrivere nel servizio associato. Il valore restituito dal metodo viene scritto nell'associazione 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(QueueFunction))]
[QueueOutput("output-queue")]
public string[] Run([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.ToString()}"};

    _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 tramite l’integrazione ASP.NET Core che scrive sia nella risposta HTTP che in un'associazione 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 alla versione 3.2.0 o successiva dell'estensione HTTP e alla versione 1.3.0 o successiva dell'estensione ASP.NET Core.

Tipi di SDK

Per alcuni tipi di associazione specifici del servizio, è possibile fornire dati di binding usando tipi di SDK e framework del servizio. Questi offrono più funzionalità rispetto a quanto può offrire una stringa serializzata o un semplice oggetto CLR (POCO). Per usare i tipi più recenti, il progetto deve essere aggiornato per l’uso delle 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 sul computer in locale, è necessario usare anche Azure Functions Core Tools, versione 4.0.5000 o successiva. È possibile controllare la versione corrente usando il comando func version.

Anche ogni estensione di trigger e binding ha un proprio requisito di versione minima, descritto negli articoli di riferimento sulle estensioni. Le associazioni specifiche del servizio seguenti forniscono tipi di SDK:

Service Trigger Associazione di input Associazione di output
BLOB di Azure Disponibile a livello generale Disponibile a livello generale Tipi di SDK non consigliati.1
Code di Azure Disponibile a livello generale L'associazione di input non esiste Tipi di SDK non consigliati.1
Bus di servizio di Azure Disponibile a livello generale L'associazione di input non esiste Tipi di SDK non consigliati.1
Hub eventi di Azure Disponibile a livello generale L'associazione di input non esiste Tipi di SDK non consigliati.1
Azure Cosmos DB Tipi di SDK non usati2 Disponibile a livello generale Tipi di SDK non consigliati.1
Tabelle di Azure Il trigger non esiste Disponibile a livello generale Tipi di SDK non consigliati.1
Griglia di eventi di Azure Disponibile a livello generale L'associazione di input non esiste Tipi di SDK non consigliati.1

1 Per gli scenari di output in cui si usa un tipo di SDK, è consigliabile creare e usare direttamente i client SDK anziché usare un'associazione di output. Vedere Registrare i client di Azure per avere un esempio di inserimento delle dipendenze.

2 Il trigger di Cosmos DB usa il feed di modifiche di Azure Cosmos DB ed espone gli elementi del feed di modifiche come tipi serializzabili JSON. L'assenza di tipi SDK è progettata per questo scenario.

Nota

Quando si usano espressioni di associazione che si basano sui dati del trigger, non è possibile usare i tipi SDK per il trigger stesso.

Trigger HTTP

I trigger HTTP consentono di richiamare una funzione da una richiesta HTTP. Si possono seguire due approcci diversi:

  • Un modello di integrazione ASP.NET Core che usa concetti noti agli sviluppatori di 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 delle app di lavoro isolate .NET.

Integrazione di ASP.NET Core

Questa sezione illustra come usare gli oggetti richiesta e risposta HTTP sottostanti usando i tipi di ASP.NET Core, tra cui HttpRequest, HttpResponse e IActionResult. Questo modello non è disponibile per le app destinate a .NET Framework, che devono invece usare il modello predefinito.

Nota

Non tutte le funzionalità di ASP.NET Core sono esposte da questo modello. In particolare, le funzionalità di routing e pipeline middleware ASP.NET Core non sono disponibili. L’integrazione 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 progetto affinché usi queste versioni specifiche del pacchetto:

  3. Program.cs Nel file aggiornare la configurazione del generatore host per chiamare ConfigureFunctionsWebApplication(). Questa operazione sostituisce ConfigureFunctionsWorkerDefaults() se si usa tale metodo in caso contrario. L'esempio seguente mostra una configurazione minima senza altre personalizzazioni:

    using Microsoft.Azure.Functions.Worker;
    using Microsoft.Extensions.Hosting;
    
    var host = new HostBuilder()
        .ConfigureFunctionsWebApplication()
        .Build();
    
    host.Run();
    
  4. Aggiornare tutte le funzioni attivate da HTTP esistenti per usare i tipi di base ASP.NET. 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 è influenzato dalla personalizzazione della configurazione della 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. Nell'esempio seguente viene illustrato come configurare JSON.NET (Newtonsoft.Json) per la serializzazione usando questo approccio:

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

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureServices(services =>
    {
        services.AddApplicationInsightsTelemetryWorkerService();
        services.ConfigureFunctionsApplicationInsights();
        services.AddMvc().AddNewtonsoftJson();
    })
    .Build();
host.Run();

Modello HTTP predefinito

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

Analogamente, la funzione restituisce un oggetto HttpResponseData, che fornisce i 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 . Il logger può essere ottenuto tramite l’inserimento delle dipendenze di un oggetto ILogger<T> o 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}");
    }

}

Il logger può essere ottenuto anche da un oggetto FunctionContext passato alla 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.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureServices(services =>
    {
        // Registers IHttpClientFactory.
        // By default this sends a lot of Information-level logs.
        services.AddHttpClient();
    })
    .ConfigureLogging(logging =>
    {
        // Disable IHttpClientFactory Informational logs.
        // Note -- you can also remove the handler that does the logging: https://github.com/aspnet/HttpClientFactory/issues/196#issuecomment-432755765 
        logging.AddFilter("System.Net.Http.HttpClient", LogLevel.Warning);
    })
    .Build();

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 oggetto HostBuilder, per impostazione predefinita, le eccezioni generate dal codice possono terminare in un oggetto RpcException. Per rimuovere questo livello aggiuntivo, impostare la proprietà EnableUserCodeException su "true" come parte della configurazione del generatore:

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

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults(builder => {}, options =>
    {
        options.EnableUserCodeException = true;
    })
    .Build();

host.Run();

Application Insights

È possibile configurare l'applicazione del processo isolato in modo che generi log direttamente in Application Insights. Questo comportamento sostituisce quello predefinito che prevede l'inoltro dei log tramite l'hosted è consigliato perché consente di controllare il modo in cui vengono generati tali log.

Installare i pacchetti

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

È possibile eseguire i comandi seguenti per aggiungere questi riferimenti al progetto:

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

Configurare l'avvio

Con i pacchetti installati, è necessario chiamare AddApplicationInsightsTelemetryWorkerService() e ConfigureFunctionsApplicationInsights() durante la configurazione del servizio nel file Program.cs, come in questo esempio:

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
    
var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureServices(services => {
        services.AddApplicationInsightsTelemetryWorkerService();
        services.ConfigureFunctionsApplicationInsights();
    })
    .Build();

host.Run();

La chiamata a ConfigureFunctionsApplicationInsights() aggiunge un oggetto ITelemetryModule, che resta in ascolto di un oggetto ActivitySource definito da Funzioni. In questo modo vengono creati i dati di telemetria delle dipendenze necessari per supportare la traccia distribuita. Per altre informazioni su AddApplicationInsightsTelemetryWorkerService() e su come usarlo, vedere Application Insights per le applicazioni del servizio di lavoro.

Gestione dei livelli di log

Importante

L'host Funzioni e il ruolo di lavoro del processo isolato hanno una configurazione separata per i livelli di log e così via. Qualsiasi configurazione di Application Insights in host.json non influirà sulla registrazione del ruolo di lavoro e, analogamente, la configurazione eseguita nel codice del ruolo di lavoro non influirà sulla registrazione dell'host. È necessario 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 del registro che indica al logger di acquisire solo avvisi e log più gravi. Se si vuole disabilitare questo comportamento, rimuovere la regola di filtro come parte della configurazione del servizio:

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

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults()
    .ConfigureServices(services => {
        services.AddApplicationInsightsTelemetryWorkerService();
        services.ConfigureFunctionsApplicationInsights();
    })
    .ConfigureLogging(logging =>
    {
        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);
            }
        });
    })
    .Build();

host.Run();

Ottimizzazioni delle prestazioni

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. Come minimo, è necessario aggiornare il progetto nel modo seguente:

  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. Aggiungere un riferimento al framework a 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 di progetto:

  <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 per le app destinate a .NET 6 o versioni successive. Per sfruttare questa ottimizzazione, è necessario abilitare in modo esplicito i segnaposto seguendo questa procedura:

  1. Aggiornare la configurazione del progetto affinché vengano usate le versioni delle dipendenze più recenti, come descritto nella sezione precedente.

  2. Settare l'impostazione dell'applicazione WEBSITE_USE_PLACEHOLDER_DOTNETISOLATED su 1, possibile tramite 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 progetto, che deve essere .NET 6 o versione successiva. A tale scopo, 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 .NET di destinazione.

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

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

Importante

Quando si imposta WEBSITE_USE_PLACEHOLDER_DOTNETISOLATED su 1, tutte le altre configurazioni dell'app per le funzioni devono essere impostate correttamente. 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 è necessaria alcuna configurazione aggiuntiva.

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 la versione 4.0 o successiva del runtime di Funzioni di Azure.

ReadyToRun richiede di compilare il progetto con l'architettura di runtime dell'app di hosting. Se non sono allineati, l'app riscontrerà un errore all'avvio. Selezionare l'identificatore di runtime da questa tabella:

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

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

Per verificare se l'app di Windows è a 32 bit o a 64 bit, è possibile 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 progetto come ReadyToRun, aggiornare il file di progetto 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 vuole impostare <RuntimeIdentifier> come parte del file di progetto, è possibile configurare questa proprietà anche come parte del movimento di pubblicazione stesso. Ad esempio, con un'app per le funzioni a 64 bit Windows, il comando dell'interfaccia della riga di comando di .NET sarà:

dotnet publish --runtime win-x64

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

Distribuire in Funzioni di Azure

Quando si distribuisce il progetto di codice della funzione in Azure, deve essere eseguito in un'app per le funzioni o in un contenitore Linux. L'app per le funzioni e le altre risorse di Azure necessarie devono essere presenti prima della distribuzione del codice.

È possibile distribuire l'app per le funzioni anche in un contenitore Linux. Per altre informazioni, vedere Uso di contenitori e Funzioni di Azure.

Creazione di risorse Azure

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

Pubblicare l'applicazione

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

Per altre informazioni, vedere Tecnologie di distribuzione in Funzioni di Azure.

Payload della distribuzione

Molti dei metodi di distribuzione usano un archivio ZIP. Se si sta creando 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
  • File eseguibile del progetto (un'app console)
  • Altri file di supporto e directory con peering a tale eseguibile

Questi file vengono generati dal processo di compilazione e non devono essere modificati direttamente.

Quando si prepara un archivio ZIP per la distribuzione, è consigliabile 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

Esistono alcuni requisiti per l'esecuzione di funzioni .NET nel modello di lavoro isolato in Azure, a seconda del sistema operativo:

Quando si crea l'app per le funzioni in Azure usando i metodi della sezione precedente, queste impostazioni obbligatorie 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.

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 è destinato a .NET Framework 4.8, l'ambito di anteprima corrente richiede alcuni passaggi manuali per abilitare il debug. 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 = new HostBuilder()
                .ConfigureFunctionsWorkerDefaults()
                .Build();

            host.Run();
        }
    }
}

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

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

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 delle versioni di .NET

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

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

È attualmente possibile usare Funzioni di Azure con le versioni .NET "Preview" o "Go-live" seguenti:

Sistema operativo Versione di anteprima di .NET
Finestre .NET 9 Preview 61, 2
Linux .NET 9 RC21, 3

1 Per usare correttamente .NET 9, il progetto deve fare riferimento alle versioni 2.x dei pacchetti principali. Se si usa Visual Studio, .NET 9 richiede la versione 17.12 o successiva.

2 Il supporto per Windows potrebbe non essere visualizzato in alcuni client durante il periodo di anteprima.

3 .NET 9 non è ancora supportato nello SKU Flex Consumption.

Vedere Versioni supportate per avere un elenco delle versioni disponibili a livello generale che è possibile usare.

Uso di un'anteprima dell’SDK .NET

Per usare Funzioni di Azure con una versione di anteprima di .NET, è necessario aggiornare il progetto tramite:

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

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

Per le app ospitate in Windows, usare il comando seguente dell'interfaccia della riga di comando di Azure. 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 Preview, che supporta la compilazione di progetti di Funzioni di Azure con gli SDK di anteprima .NET.

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

    1. Accedere a Strumenti>Opzioni, scegliere Funzioni di Azure in Progetti e soluzioni.
    2. Selezionare Controlla aggiornamenti e installare gli aggiornamenti come richiesto.
  • Durante il 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-8.0.100-preview.7.23376.3 --force fa sì che il sistema usi l’SDK .NET 8 Preview 7 durante la compilazione del progetto.

Nota

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