Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questa guida illustra come eseguire la migrazione dell'applicazione Durable Functions dal modello in-process al modello di lavoro isolato.
Avviso
Il supporto per il modello in-process termina il 10 novembre 2026. Eseguire la migrazione al modello di lavoro isolato per il supporto continuo e l'accesso alle nuove funzionalità.
Perché eseguire la migrazione?
Fine del supporto per il modello in-process
Microsoft ha annunciato che il modello in-process per .NET Azure Functions raggiunge la fine del supporto il 10 novembre 2026. Dopo questa data:
- Non vengono forniti aggiornamenti della sicurezza
- Non vengono rilasciate correzioni di bug
- Le nuove funzionalità sono disponibili solo nel modello di lavoro isolato
Vantaggi del modello di lavoro isolato
La migrazione al modello di lavoro isolato offre i vantaggi seguenti:
| Beneficio | Descrizione |
|---|---|
| Nessun conflitto di assembly | Il codice viene eseguito in un processo separato, eliminando i conflitti di versione |
| Controllo completo del processo | Controllare l'avvio, la configurazione e il middleware tramite Program.cs |
| Modelli di inserimento delle dipendenze standard | Utilizzare l'inserimento delle dipendenze familiare di .NET |
| flessibilità della versione .NET | Supporto per LTS, STS e .NET Framework |
| Supporto del middleware | Pipeline middleware completa di ASP.NET Core |
| Prestazioni migliori | integrazione di ASP.NET Core per i trigger HTTP |
| Supporto della piattaforma | Accesso al Piano di Consumo Flessibile e .NET Aspire |
Prerequisiti
Prima di avviare la migrazione, assicurarsi di disporre dei prerequisiti seguenti:
- Azure Functions Core Tools v4.x o versione successiva
- .NET 8.0 SDK (o versione di .NET di destinazione)
- Visual Studio 2022 o VS Code with Azure Functions extension
- Familiarità con i concetti di Durable Functions
Panoramica della migrazione
Il processo di migrazione prevede questi passaggi principali:
- Identificare le app di cui eseguire la migrazione
- Aggiornare il file di progetto
- Aggiungere Program.cs
- Aggiornare i riferimenti ai pacchetti
- Aggiornare il codice della funzione
- Aggiornare local.settings.json
- Testare localmente
- Deploy in Azure
Identificare le app di cui eseguire la migrazione
Usare questo script di Azure PowerShell per trovare le app di funzione della tua sottoscrizione che usano il modello in-process.
$FunctionApps = Get-AzFunctionApp
$AppInfo = @{}
foreach ($App in $FunctionApps)
{
if ($App.Runtime -eq 'dotnet')
{
$AppInfo.Add($App.Name, $App.Runtime)
}
}
$AppInfo
Le app che mostrano dotnet come runtime usano il modello in-process. Le app che utilizzano dotnet-isolated già usano il modello di lavoro isolato.
Aggiornare il file di progetto
Prima (in-process)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.1" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.13.0" />
</ItemGroup>
</Project>
Dopo (processo di lavoro isolato)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<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.17.2" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.2.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.14.1" />
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext"/>
</ItemGroup>
</Project>
Modifiche chiave
- Aggiungere
<OutputType>Exe</OutputType>- Il processo di lavoro isolato è un programma eseguibile - Aggiungere
<FrameworkReference Include="Microsoft.AspNetCore.App" />- Per l'integrazione di ASP.NET Core - Sostituire
Microsoft.NET.Sdk.Functionscon pacchettiMicrosoft.Azure.Functions.Worker.* - Sostituire
Microsoft.Azure.WebJobs.Extensions.DurableTaskconMicrosoft.Azure.Functions.Worker.Extensions.DurableTask
Aggiungere Program.cs
Creare un nuovo Program.cs file nella radice del progetto:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services => {
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
})
.Build();
host.Run();
Con i servizi personalizzati
Se si dispone di una FunctionsStartup classe, spostare la configurazione in Program.cs:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services => {
// Application Insights
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
// Your custom services (previously in FunctionsStartup)
services.AddSingleton<IMyService, MyService>();
services.AddHttpClient<IApiClient, ApiClient>();
})
.Build();
host.Run();
Eliminare FunctionsStartup
Se disponi di Startup.cs con [assembly: FunctionsStartup(...)], eliminalo dopo aver trasferito la configurazione in Program.cs.
Aggiornare i riferimenti ai pacchetti
modifiche al pacchetto Durable Functions
| Pacchetto in corso | Pacchetto di lavoro isolato |
|---|---|
Microsoft.Azure.WebJobs.Extensions.DurableTask |
Microsoft.Azure.Functions.Worker.Extensions.DurableTask |
Microsoft.DurableTask.SqlServer.AzureFunctions |
Microsoft.Azure.Functions.Worker.Extensions.DurableTask.SqlServer |
Microsoft.Azure.DurableTask.Netherite.AzureFunctions |
Microsoft.Azure.Functions.Worker.Extensions.DurableTask.Netherite |
Modifiche comuni ai pacchetti di estensione
| In corso | Lavoro isolato |
|---|---|
Microsoft.Azure.WebJobs.Extensions.Storage |
Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs, .Queues, .Tables |
Microsoft.Azure.WebJobs.Extensions.CosmosDB |
Microsoft.Azure.Functions.Worker.Extensions.CosmosDB |
Microsoft.Azure.WebJobs.Extensions.ServiceBus |
Microsoft.Azure.Functions.Worker.Extensions.ServiceBus |
Microsoft.Azure.WebJobs.Extensions.EventHubs |
Microsoft.Azure.Functions.Worker.Extensions.EventHubs |
Microsoft.Azure.WebJobs.Extensions.EventGrid |
Microsoft.Azure.Functions.Worker.Extensions.EventGrid |
Importante
Rimuovere eventuali riferimenti agli spazi dei nomi Microsoft.Azure.WebJobs.* e Microsoft.Azure.Functions.Extensions dal progetto.
Aggiornare il codice della funzione
Modifiche dello spazio dei nomi
// Before (In-Process)
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Azure.WebJobs.Extensions.Http;
// After (Isolated Worker)
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.DurableTask;
using Microsoft.DurableTask.Client;
using Microsoft.DurableTask.Entities;
Modifiche dell'attributo della funzione
// Before (In-Process)
[FunctionName("MyOrchestrator")]
// After (Isolated Worker)
[Function(nameof(MyOrchestrator))]
Modifiche delle funzioni dell'agente di orchestrazione
Prima (in-process):
[FunctionName("OrderOrchestrator")]
public static async Task<OrderResult> RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context,
ILogger log)
{
var order = context.GetInput<Order>();
await context.CallActivityAsync("ValidateOrder", order);
await context.CallActivityAsync("ProcessPayment", order.Payment);
await context.CallActivityAsync("ShipOrder", order);
return new OrderResult { Success = true };
}
Dopo (Lavoratore isolato):
[Function(nameof(OrderOrchestrator))]
public static async Task<OrderResult> OrderOrchestrator(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
ILogger logger = context.CreateReplaySafeLogger(nameof(OrderOrchestrator));
var order = context.GetInput<Order>();
await context.CallActivityAsync("ValidateOrder", order);
await context.CallActivityAsync("ProcessPayment", order.Payment);
await context.CallActivityAsync("ShipOrder", order);
return new OrderResult { Success = true };
}
Differenze principali
| Aspetto | In lavorazione | Lavoro isolato |
|---|---|---|
| Tipo di contesto | IDurableOrchestrationContext |
TaskOrchestrationContext |
| Logger | parametro ILogger |
context.CreateReplaySafeLogger() |
| Attribute | [FunctionName] |
[Function] |
Modifiche delle funzioni di attività
Prima di (In corso):
[FunctionName("ValidateOrder")]
public static bool ValidateOrder(
[ActivityTrigger] Order order,
ILogger log)
{
log.LogInformation("Validating order {OrderId}", order.Id);
return order.Items.Any() && order.TotalAmount > 0;
}
Dopo (processo di lavoro isolato)
[Function(nameof(ValidateOrder))]
public static bool ValidateOrder(
[ActivityTrigger] Order order,
FunctionContext executionContext)
{
ILogger logger = executionContext.GetLogger(nameof(ValidateOrder));
logger.LogInformation("Validating order {OrderId}", order.Id);
return order.Items.Any() && order.TotalAmount > 0;
}
Modifiche della funzione client
Prima (in-process):
[FunctionName("StartOrder")]
public static async Task<IActionResult> StartOrder(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req,
[DurableClient] IDurableOrchestrationClient client,
ILogger log)
{
var order = await req.ReadFromJsonAsync<Order>();
string instanceId = await client.StartNewAsync("OrderOrchestrator", order);
return client.CreateCheckStatusResponse(req, instanceId);
}
Dopo (processo di lavoro isolato)
[Function("StartOrder")]
public static async Task<HttpResponseData> StartOrder(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
[DurableClient] DurableTaskClient client,
FunctionContext executionContext)
{
ILogger logger = executionContext.GetLogger("StartOrder");
var order = await req.ReadFromJsonAsync<Order>();
string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(
nameof(OrderOrchestrator),
order
);
return await client.CreateCheckStatusResponseAsync(req, instanceId);
}
Modifiche al tipo di client
| In corso | Lavoro isolato |
|---|---|
IDurableOrchestrationClient |
DurableTaskClient |
StartNewAsync() |
ScheduleNewOrchestrationInstanceAsync() |
CreateCheckStatusResponse() |
CreateCheckStatusResponseAsync() |
HttpRequest / IActionResult |
HttpRequestData / HttpResponseData |
Modifiche ai criteri di ripetizione dei tentativi
In-process usa RetryOptions con CallActivityWithRetryAsync. Il lavoratore isolato usa TaskOptions con lo standard CallActivityAsync.
Prima (in-process):
var retryOptions = new RetryOptions(
firstRetryInterval: TimeSpan.FromSeconds(5),
maxNumberOfAttempts: 3);
string result = await context.CallActivityWithRetryAsync<string>(
"MyActivity", retryOptions, input);
Dopo (processo di lavoro isolato)
var retryOptions = new TaskOptions(
new TaskRetryOptions(new RetryPolicy(
maxNumberOfAttempts: 3,
firstRetryInterval: TimeSpan.FromSeconds(5))));
string result = await context.CallActivityAsync<string>(
"MyActivity", input, retryOptions);
Modifiche alle funzioni di entità
Prima (in-process):
[FunctionName(nameof(Counter))]
public static void Counter([EntityTrigger] IDurableEntityContext ctx)
{
switch (ctx.OperationName.ToLowerInvariant())
{
case "add":
ctx.SetState(ctx.GetState<int>() + ctx.GetInput<int>());
break;
case "get":
ctx.Return(ctx.GetState<int>());
break;
}
}
Dopo (processo di lavoro isolato)
[Function(nameof(Counter))]
public static Task Counter([EntityTrigger] TaskEntityDispatcher dispatcher)
{
return dispatcher.DispatchAsync<CounterEntity>();
}
public class CounterEntity
{
public int Value { get; set; }
public void Add(int amount) => Value += amount;
public int Get() => Value;
}
Informazioni di riferimento complete sulle API
Le tabelle seguenti forniscono un mapping completo tra le API di SDK dei processi di lavoro in-process 2.x e isolati.
API per il client
| In-process (2.x) | Lavoro isolato |
|---|---|
IDurableOrchestrationClient |
DurableTaskClient |
IDurableOrchestrationClient.StartNewAsync |
DurableTaskClient.ScheduleNewOrchestrationInstanceAsync |
IDurableOrchestrationClient.GetStatusAsync |
DurableTaskClient.GetInstanceAsync |
IDurableOrchestrationClient.ListInstancesAsync |
DurableTaskClient.GetAllInstancesAsync |
IDurableOrchestrationClient.TerminateAsync |
DurableTaskClient.TerminateInstanceAsync |
IDurableOrchestrationClient.SuspendAsync |
DurableTaskClient.SuspendInstanceAsync |
IDurableOrchestrationClient.ResumeAsync |
DurableTaskClient.ResumeInstanceAsync |
IDurableOrchestrationClient.RaiseEventAsync |
DurableTaskClient.RaiseEventAsync |
IDurableOrchestrationClient.RewindAsync |
DurableTaskClient.RewindInstanceAsync |
IDurableOrchestrationClient.RestartAsync |
DurableTaskClient.RestartAsync |
IDurableOrchestrationClient.PurgeInstanceHistoryAsync |
DurableTaskClient.PurgeInstanceAsync oppure PurgeAllInstancesAsync |
IDurableOrchestrationClient.CreateCheckStatusResponse |
DurableTaskClient.CreateCheckStatusResponseAsync (metodo di estensione, accetta HttpRequestData) |
IDurableOrchestrationClient.WaitForCompletionOrCreateCheckStatusResponseAsync |
DurableTaskClient.WaitForCompletionOrCreateCheckStatusResponseAsync (metodo di estensione, timeout sostituito da CancellationToken) |
IDurableOrchestrationClient.CreateHttpManagementPayload |
DurableTaskClient.CreateHttpManagementPayload (metodo di estensione) |
IDurableOrchestrationClient.MakeCurrentAppPrimaryAsync |
Rimosso |
IDurableOrchestrationClient.GetStatusAsync(IEnumerable<string>) |
Rimosso. Usare GetInstanceAsync in un ciclo o GetAllInstancesAsync con un filtro di query. |
IDurableOrchestrationClient.PurgeInstanceHistoryAsync(IEnumerable<string>) |
Rimosso. Usare PurgeInstanceAsync in un ciclo o PurgeAllInstancesAsync con un filtro. |
IDurableOrchestrationClient.RaiseEventAsync (overload tra hub di attività con taskHubName) |
Rimosso. Viene supportato solo la generazione evento per lo stesso hub di attività. |
IDurableEntityClient.SignalEntityAsync |
DurableTaskClient.Entities.SignalEntityAsync |
IDurableEntityClient.SignalEntityAsync (sovraccarico dell'hub tra attività con taskHubName, connectionName) |
Rimosso. Sono supportate solo le operazioni di entità per lo stesso hub di attività. |
IDurableEntityClient.ReadEntityStateAsync |
DurableTaskClient.Entities.GetEntityAsync |
IDurableEntityClient.ReadEntityStateAsync (overload tra hub di attività con taskHubName, connectionName) |
Rimosso. Sono supportate solo le operazioni di entità per lo stesso hub di attività. |
IDurableEntityClient.ListEntitiesAsync |
DurableTaskClient.Entities.GetAllEntitiesAsync |
IDurableEntityClient.CleanEntityStorageAsync |
DurableTaskClient.Entities.CleanEntityStorageAsync (accetta CleanEntityStorageRequest l'oggetto anziché i parametri bool) |
DurableOrchestrationStatus |
OrchestrationMetadata |
DurableOrchestrationStatus.History |
Rimosso dall'oggetto di stato. Utilizzare invece DurableTaskClient.GetOrchestrationHistoryAsync. |
PurgeHistoryResult |
PurgeResult |
OrchestrationStatusQueryCondition |
OrchestrationQuery |
OrchestrationStatusQueryResult |
AsyncPageable<OrchestrationMetadata> |
API del contesto di orchestrazione
| In-process (2.x) | Lavoro isolato |
|---|---|
IDurableOrchestrationContext |
TaskOrchestrationContext |
IDurableOrchestrationContext.GetInput<T>() |
TaskOrchestrationContext.GetInput<T>() o inserire l'input come parametro: MyOrchestration([OrchestrationTrigger] TaskOrchestrationContext context, T input) |
IDurableOrchestrationContext.SetOutput |
Rimosso. Usare il valore restituito dalla funzione orchestratore. |
IDurableOrchestrationContext.CallActivityWithRetryAsync |
TaskOrchestrationContext.CallActivityAsync con un parametro TaskOptions per i dettagli di ripetizione dei tentativi. |
IDurableOrchestrationContext.CallSubOrchestratorWithRetryAsync |
TaskOrchestrationContext.CallSubOrchestratorAsync con un TaskOptions parametro per i dettagli sui tentativi di ripetizione. |
IDurableOrchestrationContext.CallHttpAsync |
TaskOrchestrationContext.CallHttpAsync |
IDurableOrchestrationContext.CreateTimer<T>(DateTime, T, CancellationToken) |
TaskOrchestrationContext.CreateTimer(DateTime, CancellationToken). Parametro di stato rimosso. |
IDurableOrchestrationContext.WaitForExternalEvent(string) (non generico) |
Rimosso. Utilizzare il WaitForExternalEvent<T>(string, CancellationToken). |
IDurableOrchestrationContext.WaitForExternalEvent<T>(string, TimeSpan, T) (con defaultValue) |
Rimosso. Usare WaitForExternalEvent<T>(string, TimeSpan, CancellationToken), che genera TaskCanceledException in caso di timeout. |
IDurableOrchestrationContext.ParentInstanceId |
TaskOrchestrationContext.Parent.InstanceId |
IDurableOrchestrationContext.CreateReplaySafeLogger(ILogger) |
TaskOrchestrationContext.CreateReplaySafeLogger<T>() oppure TaskOrchestrationContext.CreateReplaySafeLogger(string) |
IDurableOrchestrationContext.CreateEntityProxy<T> |
Rimosso. Usare Entities.CallEntityAsync o Entities.SignalEntityAsync direttamente. |
IDurableOrchestrationContext.CallEntityAsync |
TaskOrchestrationContext.Entities.CallEntityAsync |
IDurableOrchestrationContext.SignalEntity |
TaskOrchestrationContext.Entities.SignalEntityAsync |
IDurableOrchestrationContext.LockAsync |
TaskOrchestrationContext.Entities.LockEntitiesAsync |
IDurableOrchestrationContext.IsLocked |
TaskOrchestrationContext.Entities.InCriticalSection() |
RetryOptions |
TaskOptions con TaskRetryOptions |
DurableActivityContext |
Nessun equivalente |
DurableActivityContext.GetInput<T>() |
Inserire l'input come parametro: MyActivity([ActivityTrigger] T input) |
DurableHttpRequest (spazio dei nomi WebJobs) |
DurableHttpRequest (spazio dei nomi Microsoft.Azure.Functions.Worker.Extensions.DurableTask.Http) |
DurableHttpResponse (spazio dei nomi WebJobs) |
DurableHttpResponse (spazio dei nomi Microsoft.Azure.Functions.Worker.Extensions.DurableTask.Http) |
API di entità
| In-process (2.x) | Lavoro isolato |
|---|---|
IDurableEntityContext |
TaskEntityContext |
IDurableEntityContext.EntityName |
TaskEntityContext.Id.Name |
IDurableEntityContext.EntityKey |
TaskEntityContext.Id.Key |
IDurableEntityContext.OperationName |
TaskEntityOperation.Name |
IDurableEntityContext.FunctionBindingContext |
Rimosso. Aggiungere FunctionContext come parametro di input. |
IDurableEntityContext.HasState |
TaskEntityOperation.State.HasState |
IDurableEntityContext.GetState |
TaskEntityOperation.State.GetState |
IDurableEntityContext.SetState |
TaskEntityOperation.State.SetState |
IDurableEntityContext.DeleteState |
TaskEntityOperation.State.SetState(null) |
IDurableEntityContext.GetInput |
TaskEntityOperation.GetInput |
IDurableEntityContext.Return |
Rimosso. Usare invece il valore restituito del metodo. |
IDurableEntityContext.SignalEntity |
TaskEntityContext.SignalEntity. I segnali pianificati usano SignalEntityOptions.SignalTime anziché un sovraccarico di parametri DateTime. |
IDurableEntityContext.StartNewOrchestration |
TaskEntityContext.ScheduleNewOrchestration. L'ID istanza viene impostato tramite StartOrchestrationOptions.InstanceId anziché un parametro stringa. |
IDurableEntityContext.DispatchAsync |
TaskEntityDispatcher.DispatchAsync. Parametri del costruttore rimossi; usare DI standard. |
IDurableEntityContext.BatchSize |
Rimosso |
IDurableEntityContext.BatchPosition |
Rimosso |
Modifiche comportamentali
-
Serializzazione: il serializzatore predefinito è stato modificato da
Newtonsoft.JsonaSystem.Text.Json. Per altre informazioni, vedere Serializzazione e persistenza in Durable Functions.
Avviso
ContinueAsNuova modifica predefinita: il preserveUnprocessedEvents parametro predefinito è stato modificato da false (2.x) a true (isolato). Se l'orchestrazione usa ContinueAsNew e si basa su eventi non elaborati rimossi, passare preserveUnprocessedEvents: false in modo esplicito.
Annotazioni
Cambio del valore predefinito di RestartAsync: il parametro predefinito è stato modificato da true (2.x) a false (isolato). Se il codice chiama RestartAsync e dipende da un nuovo ID istanza generato, passare restartWithNewInstanceId: true in modo esplicito.
-
Rimozione del proxy di entità:
CreateEntityProxy<T>e gli overload del delegatoSignalEntityAsync<TEntityInterface>(Action<T>)tipizzato non sono disponibili nel processo di lavoro isolato. ChiamareEntities.CallEntityAsyncoEntities.SignalEntityAsyncdirettamente con nomi di operazione basati su stringa anziché usare interfacce proxy tipate. -
WaitForCompletionOrCreateCheckStatusResponseAsync: il
timeoutparametro è stato rimosso. Usare invece unCancellationTokencon un timeout di cancellazione. -
Operazioni tra hub di attività rimosse: gli overload in-process che accettano i parametri
taskHubNameeconnectionName(inRaiseEventAsync,SignalEntityAsynceReadEntityStateAsync) non sono disponibili in un processo di lavoro isolato. Sono supportate solo le operazioni dello stesso task hub. -
Operazioni batch per ID rimosse: gli overload
GetStatusAsync(IEnumerable<string>)ePurgeInstanceHistoryAsync(IEnumerable<string>)non sono disponibili nel processo di lavoro isolato. UsareGetAllInstancesAsynccon un filtroOrchestrationQueryo chiamaGetInstanceAsync/PurgeInstanceAsyncsingolarmente. -
Cronologia di orchestrazione spostata:
DurableOrchestrationStatus.History(l'elementoJArrayincorporato) non fa più parte dell'oggetto di stato. Usare l'API separataDurableTaskClient.GetOrchestrationHistoryAsyncper recuperare la cronologia dell'orchestrazione. -
Parametri del costruttore DispatchAsync di entità: l'overload dei parametri del costruttore
DispatchAsync<T>(params object[])non è disponibile. Le classi di entità vengono attivate tramite l'inserimento delle dipendenze standard. Registra le dipendenze dell'entità inProgram.cs. -
Modifiche al filtro delle query di entità:
EntityQuery.EntityNameviene sostituito daEntityQuery.InstanceIdStartsWitheEntityQuery.IncludeDeletedviene sostituito daEntityQuery.IncludeTransient. -
Modifica della firma CleanEntityStorageAsync: invece di
(bool removeEmptyEntities, bool releaseOrphanedLocks, CancellationToken), la versione isolata accetta un oggetto con le proprietàRemoveEmptyEntitieseReleaseOrphanedLocks. -
Nuove API nel processo di lavoro isolato:
DurableTaskClient.GetOrchestrationHistoryAsynce il metodo di estensioneTaskOrchestrationContext.GetFunctionContext()sono disponibili nel processo di lavoro isolato, ma non hanno un equivalente nell'ambiente in-process.
Aggiornare local.settings.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
"DURABLE_TASK_SCHEDULER_CONNECTION_STRING": "Endpoint=http://localhost:8080;Authentication=None"
}
}
La modifica della chiave è FUNCTIONS_WORKER_RUNTIME da dotnet a dotnet-isolated.
Testare localmente
Avviare l'emulatore
docker run -d -p 8080:8080 -p 8082:8082 mcr.microsoft.com/dts/dts-emulator:latest
Eseguire l'applicazione di funzioni
func start
Verificare la funzionalità
Testare tutte le orchestrazioni, le attività e le entità per assicurarsi che funzionino correttamente:
- Avviare un'orchestrazione con un trigger HTTP
- Monitorare lo stato di orchestrazione
- Verificare l'ordine di esecuzione dell'attività
- Testare le operazioni di entità, se applicabile
- Controllare i dati di telemetria di Application Insights
Distribuire in Azure
Consigliato: usare gli slot di distribuzione
Usare gli slot di distribuzione per minimizzare il downtime
- Creare uno slot di staging per l'app per le funzioni.
-
Aggiornare la configurazione dello slot di staging:
- Impostare
FUNCTIONS_WORKER_RUNTIMEsudotnet-isolated. - Aggiornare .NET versione dello stack, se necessario.
- Impostare
- Distribuire il codice migrato nello slot di staging.
- Eseguire un test approfondito nello slot di staging.
- Eseguire lo scambio di slot per spostare le modifiche nell'ambiente di produzione.
Aggiornare le impostazioni dell'applicazione
Nel portale di Azure o tramite l'interfaccia della riga di comando:
az functionapp config appsettings set \
--name <FUNCTION_APP_NAME> \
--resource-group <RESOURCE_GROUP> \
--settings FUNCTIONS_WORKER_RUNTIME=dotnet-isolated
Aggiornare la configurazione dello stack
Se la destinazione è una versione .NET diversa:
az functionapp config set \
--name <FUNCTION_APP_NAME> \
--resource-group <RESOURCE_GROUP> \
--net-framework-version v8.0
Problemi comuni relativi alla migrazione
Problema: Errori di caricamento dell'assembly
Sintomo:Could not load file or assembly errori.
Soluzione: rimuovere tutti i Microsoft.Azure.WebJobs.* riferimenti al pacchetto e sostituirli con processi di lavoro isolati equivalenti.
Problema: Impossibile trovare l'attributo di associazione
Sintomo:The type or namespace 'QueueTrigger' could not be found
Soluzione: aggiungere il pacchetto di estensione appropriato e aggiornare le istruzioni using:
// Add using statement
using Microsoft.Azure.Functions.Worker;
// Install package
// dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues
Problema: IDurableOrchestrationContext non trovato
Sintomo:The type or namespace 'IDurableOrchestrationContext' could not be found
Soluzione: Sostituire con TaskOrchestrationContext:
using Microsoft.DurableTask;
[Function(nameof(MyOrchestrator))]
public static async Task MyOrchestrator([OrchestrationTrigger] TaskOrchestrationContext context)
{
// ...
}
Problema: differenze di serializzazione JSON
Sintomo: Errori di serializzazione o formati di dati imprevisti
Soluzione: Il modello isolato utilizza System.Text.Json per impostazione predefinita. Configurare la serializzazione in Program.cs:
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services => {
services.Configure<JsonSerializerOptions>(options => {
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
})
.Build();
Per usare invece Newtonsoft.Json:
services.Configure<WorkerOptions>(options => {
options.Serializer = new NewtonsoftJsonObjectSerializer();
});
Problema: Migrazione delle impostazioni di serializzazione personalizzate
Sintomo: è stato usato IMessageSerializerSettingsFactory nel modello in-process per personalizzare la serializzazione JSON per input, output o stato dell'entità di orchestrazione ed è necessario l'elemento equivalente nel processo di lavoro isolato.
Soluzione: L'interfaccia IMessageSerializerSettingsFactory non è disponibile nel worker isolato. Configurare invece il serializzatore a livello di processo di lavoro in Program.cs:
Prima di (In-Process):
// Startup.cs
[assembly: FunctionsStartup(typeof(MyStartup))]
public class MyStartup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSingleton<IMessageSerializerSettingsFactory, CustomSerializerSettingsFactory>();
}
}
Dopo (Lavoratore Isolato)
// Program.cs
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services =>
{
services.Configure<WorkerOptions>(options =>
{
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.None,
DateFormatHandling = DateFormatHandling.IsoDateFormat,
};
options.Serializer = new NewtonsoftJsonObjectSerializer(settings);
});
})
.Build();
Annotazioni
Questo approccio richiede i pacchetti NuGet Newtonsoft.Json e Azure.Core.Serialization. L'impostazione WorkerOptions.Serializer si applica a livello globale a tutti gli elementi serializzati dall'estensione Durable Functions. Per altri dettagli, vedere Serializzazione e persistenza in Durable Functions.
Checklist
Usare questo elenco di controllo per garantire una migrazione completa:
- File di progetto aggiornato con
<OutputType>Exe</OutputType> - Sostituito
Microsoft.NET.Sdk.Functionscon i pacchetti di lavoro - Sostituito
Microsoft.Azure.WebJobs.Extensions.DurableTaskcon un pacchetto isolato - Creato
Program.cscon la configurazione dell'host - Classe rimossa
FunctionsStartup(se presente) - Aggiornati tutti
[FunctionName]a[Function] - Sostituito
IDurableOrchestrationContextconTaskOrchestrationContext - Sostituito
IDurableOrchestrationClientconDurableTaskClient - Registrazione aggiornata per l'uso di DI o
FunctionContext - Aggiornato il runtime di
local.settings.jsoncondotnet-isolated - Sono state rimosse tutte le istruzioni using di
Microsoft.Azure.WebJobs.* - Sono state aggiunte istruzioni using di
Microsoft.Azure.Functions.Worker - Sostituito
CreateEntityProxy<T>con chiamate diretteCallEntityAsync/SignalEntityAsync - Sostituzione degli overload delle operazioni tra hub di attività (se in uso)
- Sostituite le chiamate batch
GetStatusAsync/PurgeInstanceHistoryAsyncper ID con chiamate singole o basate su filtro - Accesso migrato
DurableOrchestrationStatus.HistoryaGetOrchestrationHistoryAsync - Parametri del costruttore
DispatchAsyncdi entità aggiornati per l'uso dell'inserimento delle dipendenze - Tutte le funzioni sono state testate in locale
- Distribuito nello slot di staging e verificato
- Scambiato in produzione
Passaggi successivi
- Panoramica del processo di lavoro isolato di .NET
- Panoramica di Durable Functions per il processo di lavoro .NET isolato
- Durable Functions modelli e concetti tecnici
Risorse aggiuntive
- Guida ufficiale alla migrazione Microsoft
- Differenze del modello di lavoro isolato
- Guida agli unit test per Durable Functions (ambiente isolato)
- Serializzazione e persistenza in Durable Functions
- Controllo delle versioni in Durable Functions
- Distribuzione senza tempi di inattività per Durable Functions
- Configurare il Schedulatore di Attività Durevoli
- Esempi di codice per Durable Functions