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 completa di middleware 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-Processo)
<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 (Isolated Worker)
<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
- Add
<OutputType>Exe</OutputType>- il lavoratore isolato è un 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 di (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 (Isolated Worker):
[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 di (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 (Isolated Worker):
[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 di (In-Process):
var retryOptions = new RetryOptions(
firstRetryInterval: TimeSpan.FromSeconds(5),
maxNumberOfAttempts: 3);
string result = await context.CallActivityWithRetryAsync<string>(
"MyActivity", retryOptions, input);
Dopo (Isolated Worker):
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 di (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 (Isolated Worker):
[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 una corrispondenza completa tra l'SDK in-process 2.x e le API dell'SDK del worker isolato.
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. Utilizzare GetInstanceAsync in un ciclo iterativo o GetAllInstancesAsync con un filtro di query. |
IDurableOrchestrationClient.PurgeInstanceHistoryAsync(IEnumerable<string>) |
Rimosso. Usare PurgeInstanceAsync in un ciclo o PurgeAllInstancesAsync con un filtro. |
IDurableOrchestrationClient.RaiseEventAsync (sovraccarico del hub tra attività con taskHubName) |
Rimosso. Viene supportato solo l'evento di attivazione 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à del "same-task-hub". |
IDurableEntityClient.ReadEntityStateAsync |
DurableTaskClient.Entities.GetEntityAsync |
IDurableEntityClient.ReadEntityStateAsync (sovraccarico dell'hub incarichi incrociati con taskHubName, connectionName) |
Rimosso. Sono supportate solo le operazioni di entità del "same-task-hub". |
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 TaskOptions parametro 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 invece l'inserimento delle dipendenze 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 scartati, passa esplicitamente preserveUnprocessedEvents: false.
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 delegato tipizzatoSignalEntityAsync<TEntityInterface>(Action<T>)non sono disponibili nel worker 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 attività rimosse: gli overload in-process che accettano
taskHubNameeconnectionName(inRaiseEventAsync,SignalEntityAsynceReadEntityStateAsync) non sono disponibili in contesto di lavoro isolato. Sono supportate solo le operazioni dello stesso task hub. -
Operazioni batch per ID rimosse: gli overload e
GetStatusAsync(IEnumerable<string>)in-processPurgeInstanceHistoryAsync(IEnumerable<string>)non sono disponibili nel ruolo di lavoro isolato. UsareGetAllInstancesAsynccon un filtroOrchestrationQueryo chiamaGetInstanceAsync/PurgeInstanceAsyncsingolarmente. -
Cronologia orchestrazione spostata:
DurableOrchestrationStatus.History(l'incorporatoJArray) non fa più parte dell'oggetto stato. Usare l'API separataDurableTaskClient.GetOrchestrationHistoryAsyncper recuperare la cronologia dell'orchestrazione. -
Parametri del costruttore DispatchAsync rimossi: l'overload
DispatchAsync<T>(params object[])del parametro del costruttore 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 worker isolato:
DurableTaskClient.GetOrchestrationHistoryAsynce ilTaskOrchestrationContext.GetFunctionContext()metodo di estensione sono disponibili nel worker isolato, ma non hanno equivalenti 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: Assicurarsi di rimuovere tutti i riferimenti al Microsoft.Azure.WebJobs.* pacchetto e sostituirli con equivalenti di lavoratori isolati.
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 di importazione:
// 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 di orchestrazione, output o stato dell'entità e hai bisogno dell'equivalente nel worker isolato.
Soluzione: L'interfaccia IMessageSerializerSettingsFactory non è disponibile nel worker isolato. Configurare invece il serializzatore a livello 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 - Aggiornato il logging per utilizzare Dependency Injection o
FunctionContext - Aggiornato il runtime di
local.settings.jsoncondotnet-isolated - Tutte le istruzioni using
Microsoft.Azure.WebJobs.*sono state rimosse - Aggiunte istruzioni using
Microsoft.Azure.Functions.Worker - Sostituito
CreateEntityProxy<T>con chiamate diretteCallEntityAsync/SignalEntityAsync - Sostituzione degli overload delle operazioni tra più attività (se usato)
- Sostituite le chiamate batch
GetStatusAsync/PurgeInstanceHistoryAsyncby-ID con chiamate singole o basate su filtro - Accesso migrato
DurableOrchestrationStatus.HistoryaGetOrchestrationHistoryAsync - Parametri del costruttore di entità
DispatchAsyncaggiornati 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 .NET ruolo di lavoro isolato
- Durable Functions modelli e concetti tecnici
Risorse aggiuntive
- Guida ufficiale alla migrazione Microsoft
- Differenze del modello di lavoro isolato
- Guida ai test unità per Durable Functions (isolato)
- Serializzazione e persistenza in Durable Functions
- Versioning in Durable Functions
- distribuzione Zero-downtime per Durable Functions
- Configurare il Schedulatore di Attività Durevoli
- Esempi di codice per Durable Functions