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-process4 |
---|---|---|
Funzioni 4.x1 | .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 la fine del supporto ufficiale il 12 novembre 2024. .NET 7 è stato precedentemente supportato nel modello di lavoro 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 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.
4 Il supporto termina per il modello in-process 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
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 o versione successiva, l'app deve fare riferimento alla versione 2.0.0 o successiva di entrambi i pacchetti.
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:
- L'SDK include configurazioni predefinite per le compilazioni di contenitori SDK.
- L'SDK include il supporto per
dotnet run
quando è installato Funzioni di Azure Core Tools.
- 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 usanoIHostApplicationBuilder
. 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 presentestring[]
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 suIncludeEmptyEntriesInMessagePayload
false
nella configurazione delWorkerOptions
servizio. - La
ILoggerExtensions
classe viene rinominata inFunctionsLoggerExtensions
. La ridenominazione impedisce un errore di chiamata ambiguo quando si usaLogMetric()
in un'istanzaILogger
di . - Per le app che usano
HttpResponseData
, ilWriteAsJsonAsync()
metodo non imposta più il codice di stato su200 OK
. Nella versione 1.x, questo overrode altri codici di errore impostati.
- Questa versione aggiunge il supporto per
- Le versioni 2.x rilasciano il supporto tfm di .NET 5.
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://learn.microsoft.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 chiamareAddApplicationInsightsTelemetryWorkerService()
eConfigureFunctionsApplicationInsights()
nel delegatoConfigureServices()
. 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 , HostBuilder
chiamare 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:
- Binding, contrassegnati come tali definendo i parametri come attributi. La funzione deve contenere esattamente un parametro trigger.
- Un contesto di ambiente esecuzione, che fornisce informazioni sulla chiamata corrente.
- Un token di annullamento, usato per l'arresto normale.
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}"};
_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:
Aggiungere un riferimento nel progetto al pacchetto Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore, versione 1.0.0 o successiva.
Aggiornare il progetto affinché usi queste versioni specifiche del pacchetto:
- Microsoft.Azure.Functions.Worker.Sdk, versione 1.11.0. o versioni successive
- Microsoft.Azure.Functions.Worker, versione 1.16.0 o successiva.
Program.cs
Nel file aggiornare la configurazione del generatore host per chiamareConfigureFunctionsWebApplication()
. Questa operazione sostituisceConfigureFunctionsWorkerDefaults()
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();
Aggiornare tutte le funzioni attivate da HTTP esistenti per usare i tipi di base ASP.NET. Questo esempio mostra
HttpRequest
eIActionResult
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 il comportamento predefinito dell'inoltro dei log tramite l'host. A meno che non si usi .NET Aspire, è consigliabile configurare l'integrazione diretta di Application Insights perché consente di controllare come vengono generati tali log.
L'integrazione di Application Insights non è abilitata per impostazione predefinita in tutte le esperienze di installazione. Alcuni modelli creeranno progetti di Funzioni con i pacchetti necessari e il codice di avvio commentati. Se si vuole usare l'integrazione di Application Insights, è possibile rimuovere il commento da queste righe in Program.cs
e nel file del .csproj
progetto. Le istruzioni nella parte restante di questa sezione descrivono anche come abilitare l'integrazione.
Se il progetto fa parte di un'orchestrazione .NET Aspire, usa invece OpenTelemetry per il monitoraggio. Non è consigliabile abilitare l'integrazione diretta di Application Insights all'interno di progetti .NET Aspire. Configurare invece l'utilità di esportazione OpenTelemetry di Monitoraggio di Azure come parte del progetto predefinito del servizio. Se il progetto di Funzioni usa l'integrazione di Application Insights in un contesto .NET Aspira, l'applicazione avrà esito negativo all'avvio.
Installare i pacchetti
Per scrivere i log dal codice direttamente in Application Insights, aggiungere riferimenti a questi pacchetti nel progetto:
- Microsoft.Azure.Functions.Worker.ApplicationInsights, versione 1.0.0 o successiva.
- Microsoft.ApplicationInsights.WorkerService.
È 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:
- Aggiornare Microsoft.Azure.Functions.Worker alla versione 1.19.0 o successiva.
- Aggiornare Microsoft.Azure.Functions.Worker.Sdk alla versione 1.16.4 o successiva.
- 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:
Aggiornare la configurazione del progetto affinché vengano usate le versioni delle dipendenze più recenti, come descritto nella sezione precedente.
Settare l'impostazione dell'applicazione
WEBSITE_USE_PLACEHOLDER_DOTNETISOLATED
su1
, 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.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 esempiov8.0
, in base alla versione .NET di destinazione.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:
- Visual Studio: Visual Studio può creare automaticamente 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.
- Interfaccia della riga di comando di Azure: è possibile usare l'interfaccia della riga di comando di Azure per creare le risorse necessarie in Azure.
- Azure PowerShell: è possibile usare Azure PowerShell per creare le risorse necessarie in Azure.
- Modelli di distribuzione: è possibile usare modelli ARM e file Bicep per automatizzare la distribuzione delle risorse necessarie in Azure. Assicurarsi che il modello includa le impostazioni necessarie.
- Portale di Azure: è possibile creare le risorse necessarie nel portale di Azure.
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:
- Visual Studio: distribuzione manuale semplice durante lo sviluppo.
- Visual Studio Code: distribuzione manuale semplice durante lo sviluppo.
- Azure Functions Core Tools: distribuire il file di progetto dalla riga di comando.
- Distribuzione continua: utile per la manutenzione continua, spesso in uno slot di staging.
- Modelli di distribuzione: è possibile usare modelli ARM o file Bicep per automatizzare le distribuzioni dei pacchetti.
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:
- FUNCTIONS_WORKER_RUNTIME deve essere impostato su un valore di
dotnet-isolated
. - netFrameworkVersion deve essere impostato sulla versione desiderata.
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.
.NET Aspire (Anteprima)
.NET Aspire è uno stack di opinioni che semplifica lo sviluppo di applicazioni distribuite nel cloud. È possibile integrare progetti di modelli di lavoro isolati .NET 8 e .NET 9 nelle orchestrazioni Di Aspira 9.0 usando il supporto per l'anteprima. La sezione descrive i requisiti di base per l'integrazione.
Questa integrazione richiede una configurazione specifica:
- Usare aspirare 9.0 o versione successiva e .NET 9 SDK. Aspira 9.0 supporta i framework .NET 8 e .NET 9.
- Se si usa Visual Studio, eseguire l'aggiornamento alla versione 17.12 o successiva. È anche necessario avere la versione più recente degli strumenti di Funzioni per Visual Studio. Per verificare la disponibilità di aggiornamenti, passare a Opzioni strumenti>, scegliere Funzioni di Azure in Progetti e soluzioni. Selezionare Controlla aggiornamenti e installare gli aggiornamenti come richiesto.
- Nel progetto host dell'app Aspirare:
- È necessario fare riferimento a Aspire.Hosting.Azure.Functions.
- È necessario disporre di un riferimento al progetto di Funzioni.
- Nell'host dell'app
Program.cs
è necessario includere anche il progetto chiamandoAddAzureFunctionsProject<TProject>()
suIDistributedApplicationBuilder
. Questo metodo viene usato anziché perAddProject<TProject>()
altri tipi di progetto. Se si usaAddProject<TProject>()
solo , il progetto Funzioni non verrà avviato correttamente.
- Nel progetto Funzioni:
- È necessario fare riferimento alle versioni 2.x di Microsoft.Azure.Functions.Worker e Microsoft.Azure.Functions.Worker.Sdk. È anche necessario aggiornare tutti i riferimenti necessari
Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore
anche alla versione 2.x. - È consigliabile
Program.cs
usare la versione dell'avvioIHostApplicationBuilder
dell'istanza host. - Se si desidera usare le impostazioni predefinite del servizio Aspirare, è necessario includere un riferimento al progetto per impostazione predefinita del servizio. Prima di compilare
IHostApplicationBuilder
inProgram.cs
, è necessario includere anche una chiamata abuilder.AddServiceDefaults()
. - Non è consigliabile mantenere la configurazione in
local.settings.json
, a parte l'impostazioneFUNCTIONS_WORKER_RUNTIME
, che deve rimanere "dotnet-isolated". È necessario impostare altre configurazioni tramite il progetto host dell'app. - È consigliabile rimuovere tutte le integrazioni dirette di Application Insights. Il monitoraggio in Aspira è invece gestito tramite il supporto OpenTelemetry.
- È necessario fare riferimento alle versioni 2.x di Microsoft.Azure.Functions.Worker e Microsoft.Azure.Functions.Worker.Sdk. È anche necessario aggiornare tutti i riferimenti necessari
L'esempio seguente mostra un valore minimo Program.cs
per un progetto Host app:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject");
builder.Build().Run();
L'esempio seguente mostra un valore minimo Program.cs
per un progetto Functions usato in Aspira:
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.AddServiceDefaults();
builder.ConfigureFunctionsWebApplication();
builder.Build().Run();
Ciò non include la configurazione predefinita di Application Insights visualizzata in molti degli altri Program.cs
esempi di questo articolo. L'integrazione OpenTelemetry di Aspire viene invece configurata tramite la builder.AddServiceDefaults()
chiamata.
Considerazioni e procedure consigliate per l'integrazione di .NET Aspire
Quando si valuta .NET Aspira con Funzioni di Azure, tenere presente quanto segue:
- Il supporto per Funzioni di Azure con .NET Aspire è attualmente in anteprima. Durante il periodo di anteprima, quando si pubblica la soluzione Aspira in Azure, i progetti di Funzioni vengono distribuiti come risorse di App Azure Container senza ridimensionamento basato su eventi. Funzioni di Azure supporto non è disponibile per le app distribuite in questa modalità.
- La configurazione di trigger e binding tramite Aspira è attualmente limitata a integrazioni specifiche. Per informazioni dettagliate, vedere Configurazione della connessione con Aspira.
- È consigliabile
Program.cs
usare la versione dell'avvioIHostApplicationBuilder
dell'istanza host. In questo modo è possibile chiamarebuilder.AddServiceDefaults()
per aggiungere le impostazioni predefinite del servizio .NET Aspire al progetto funzioni. - L'aspirare usa OpenTelemetry per il monitoraggio. È possibile configurare aspirare per esportare i dati di telemetria in Monitoraggio di Azure tramite il progetto predefinito del servizio. In molti altri contesti di Funzioni di Azure, è possibile includere l'integrazione diretta con Application Insights registrando il servizio di lavoro di telemetria. Questa opzione non è consigliata in Aspirare e può causare errori di runtime con la versione 2.22.0 di
Microsoft.ApplicationInsights.WorkerService
. È consigliabile rimuovere tutte le integrazioni dirette di Application Insights dal progetto di Funzioni quando si usa Aspira. - Per i progetti di Funzioni inseriti in un'orchestrazione Aspira, la maggior parte della configurazione dell'applicazione deve provenire dal progetto host dell'app Aspira. In genere è consigliabile evitare di impostare elementi in
local.settings.json
, ad eccezione dell'impostazioneFUNCTIONS_WORKER_RUNTIME
. Se la stessa variabile di ambiente è impostata dalocal.settings.json
e Aspira, il sistema usa la versione Aspira. - Non configurare l'emulatore di archiviazione per le connessioni in
local.settings.json
. Molti modelli di avvio di Funzioni includono l'emulatore come predefinito perAzureWebJobsStorage
. Tuttavia, la configurazione dell'emulatore può richiedere ad alcuni IDE di avviare una versione dell'emulatore in conflitto con la versione usata da Aspire.
Configurazione della connessione con Aspira
Funzioni di Azure richiede una connessione di archiviazione host (AzureWebJobsStorage
) per diversi comportamenti principali. Quando si chiama AddAzureFunctionsProject<TProject>()
nel progetto host dell'app, viene creata e fornita una connessione predefinita AzureWebJobsStorage
al progetto Funzioni. Questa connessione predefinita usa l'emulatore di archiviazione per le esecuzioni di sviluppo locale e effettua automaticamente il provisioning di un account di archiviazione quando viene distribuito. Per un controllo aggiuntivo, è possibile sostituire questa connessione chiamando .WithHostStorage()
la risorsa del progetto Funzioni.
L'esempio seguente mostra un valore minimo Program.cs
per un progetto host dell'app che sostituisce l'archiviazione host:
var builder = DistributedApplication.CreateBuilder(args);
var myHostStorage = builder.AddAzureStorage("myHostStorage");
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithHostStorage(myHostStorage);
builder.Build().Run();
Nota
Quando l'aspirare effettua il provisioning dell'archiviazione host in modalità di pubblicazione, per impostazione predefinita crea assegnazioni di ruolo per i ruoli Collaboratore account di archiviazione, Collaboratore ai dati dei BLOB di archiviazione, Collaboratore dati coda archiviazione e Collaboratore dati tabella di archiviazione.
I trigger e le associazioni fanno riferimento alle connessioni in base al nome. Alcune integrazioni aspirabili sono abilitate per fornire queste funzionalità tramite una chiamata a WithReference()
sulla risorsa del progetto:
Integrazione aspirare | Note |
---|---|
BLOB di Azure | Quando l'aspirare effettua il provisioning della risorsa, per impostazione predefinita crea assegnazioni di ruolo per i ruoli Collaboratore ai dati dei BLOB di archiviazione, Collaboratore ai dati della coda di archiviazione e Collaboratore dati tabella di archiviazione. |
Code di Azure | Quando l'aspirare effettua il provisioning della risorsa, per impostazione predefinita crea assegnazioni di ruolo per i ruoli Collaboratore ai dati dei BLOB di archiviazione, Collaboratore ai dati della coda di archiviazione e Collaboratore dati tabella di archiviazione. |
Hub eventi di Azure | Quando l'aspirare effettua il provisioning della risorsa, per impostazione predefinita viene creata un'assegnazione di ruolo usando il ruolo proprietario dei dati Hub eventi di Azure. |
Bus di servizio di Azure | Quando l'aspirare effettua il provisioning della risorsa, per impostazione predefinita viene creata un'assegnazione di ruolo usando il ruolo proprietario dei dati bus di servizio di Azure. |
L'esempio seguente mostra un valore minimo Program.cs
per un progetto host dell'app che configura un trigger della coda. In questo esempio, il trigger della coda corrispondente ha la proprietà Connection
impostata su "MyQueueTriggerConnection".
var builder = DistributedApplication.CreateBuilder(args);
var myAppStorage = builder.AddAzureStorage("myAppStorage").RunAsEmulator();
var queues = myAppStorage.AddQueues("queues");
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithReference(queues, "MyQueueTriggerConnection");
builder.Build().Run();
Per altre integrazioni, chiama per WithReference
impostare la configurazione in modo diverso, rendendola disponibile per le integrazioni client Di Aspira, ma non per trigger e associazioni. Per queste integrazioni, è necessario chiamare WithEnvironment()
per passare le informazioni di connessione per il trigger o l'associazione da risolvere. L'esempio seguente illustra come impostare la variabile di ambiente "MyBindingConnection" per una risorsa che espone un'espressione stringa di connessione:
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithEnvironment("MyBindingConnection", otherIntegration.Resource.ConnectionStringExpression);
È possibile configurare sia WithReference()
che WithEnvironment()
se si vuole usare una connessione sia dalle integrazioni client aspirate che dal sistema trigger e binding.
Per alcune risorse, la struttura di una connessione potrebbe essere diversa tra l'esecuzione locale e la pubblicazione in Azure. Nell'esempio precedente, otherIntegration
potrebbe essere una risorsa eseguita come emulatore, quindi ConnectionStringExpression
restituirebbe un emulatore stringa di connessione. Tuttavia, quando la risorsa viene pubblicata, aspirare potrebbe configurare una connessione basata sull'identità e ConnectionStringExpression
restituirebbe l'URI del servizio. In questo caso, per configurare le connessioni basate su identità per Funzioni di Azure, potrebbe essere necessario specificare un nome di variabile di ambiente diverso. Nell'esempio seguente viene usato per aggiungere in modo condizionale il suffisso builder.ExecutionContext.IsPublishMode
necessario:
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithEnvironment("MyBindingConnection" + (builder.ExecutionContext.IsPublishMode ? "__serviceUri" : ""), otherIntegration.Resource.ConnectionStringExpression);
A seconda dello scenario, potrebbe anche essere necessario modificare le autorizzazioni che verranno assegnate per una connessione basata su identità. È possibile usare il ConfigureConstruct<T>()
metodo per personalizzare il modo in cui aspirare configura l'infrastruttura quando pubblica il progetto.
Per informazioni dettagliate sui formati di connessione supportati e sulle autorizzazioni necessarie per tali formati, consultare le pagine di riferimento di ogni binding.
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, è necessario eseguire 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.
Funzioni di Azure attualmente non funziona con le versioni .NET "Preview" o "Go-live". 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:
- Installazione della versione pertinente dell’SDK .NET per lo sviluppo
- 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:
- Accedere a Strumenti>Opzioni, scegliere Funzioni di Azure in Progetti e soluzioni.
- 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
.- Eseguire il comando
dotnet --list-sdks
e prendere nota della versione di anteprima attualmente in uso durante lo sviluppo locale. - 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.
- Eseguire il comando
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.