Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Este guia guia-o na migração da sua aplicação de .NET Durable Functions do modelo em processo para o modelo de trabalhador isolado. O modelo em processo chega ao fim do suporte a 10 de novembro de 2026. Após essa data, não são fornecidas atualizações de segurança nem correções de bugs. O modelo de trabalhador isolado também lhe dá controlo total de processos, injeção padrão de dependência .NET e acesso às funcionalidades mais recentes da plataforma.
Advertência
O suporte ao modelo em processo termina a 10 de novembro de 2026. Recomendamos migrar agora. Para contexto sobre o modelo do trabalhador isolado, veja .NET visão geral do processo do trabalhador isolado.
Lista de verificação da migração
Use a seguinte lista de verificação para acompanhar o seu progresso em cada etapa da migração:
| Step | Seção |
|---|---|
| 1. Verificar os pré-requisitos | Prerequisites |
| 2. Atualizar o ficheiro do projeto | Atualizar o ficheiro do projeto |
| 3. Adicionar Program.cs | Adicionar Program.cs |
| 4. Atualizar referências de pacotes | Atualizar referências de pacotes |
| 5. Atualizar código de função | Atualizar código de função |
| 6. Atualizar local.settings.json | Atualizar local.settings.json |
| 7. Testar localmente | Testar localmente |
| 8. Implementar no Azure | Implementar no Azure |
Pré-requisitos
- Funções do Azure Core Tools v4.x ou posterior
- .NET 8.0 SDK (ou a tua versão .NET alvo)
- Visual Studio 2022 ou VS Code com Funções do Azure extensão
Identificar aplicações a migrar (opcional)
Se não tiveres a certeza de que aplicações ainda usam o modelo em processo, executa este script Azure PowerShell:
$FunctionApps = Get-AzFunctionApp
$AppInfo = @{}
foreach ($App in $FunctionApps)
{
if ($App.Runtime -eq 'dotnet')
{
$AppInfo.Add($App.Name, $App.Runtime)
}
}
$AppInfo
As aplicações que mostram dotnet-isolated já usam o modelo de trabalhador isolado.
Atualizar o arquivo de projeto
Antes (em 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>
Depois (trabalhador isolado)
<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>
As principais alterações são a mudança para um tipo de saída executável e a substituição de todos os pacotes Microsoft.Azure.WebJobs.* pelos seus equivalentes Microsoft.Azure.Functions.Worker.*.
Adicionar Program.cs
O modelo de trabalhador isolado requer um Program.cs ponto de entrada. Cria este ficheiro na raiz do teu projeto. Se tiver uma FunctionsStartup classe em Startup.cs, mova essas registos de serviço para o bloco ConfigureServices e elimina Startup.cs.
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services => {
services.AddApplicationInsightsTelemetryWorkerService();
services.ConfigureFunctionsApplicationInsights();
// Add your custom services here (previously in FunctionsStartup)
// services.AddSingleton<IMyService, MyService>();
})
.Build();
host.Run();
Atualizar referências de pacotes
Mapeamento de pacotes das Durable Functions
| Pacote em andamento | Pacote de trabalhadores isolados |
|---|---|
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 |
Mapeamento comum de pacotes de extensões
| Em andamento | Trabalhador isolado |
|---|---|
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
Remova quaisquer referências a Microsoft.Azure.WebJobs.* namespaces e Microsoft.Azure.Functions.Extensions do seu projeto.
Atualizar código de função
Esta secção cobre as alterações de código para cada tipo de Durable Functions. Vai para a secção dos tipos de funções que a tua aplicação utiliza:
- Alterações no espaço de nomes
- Funções de orquestrador
- Funções de atividade
- Funções do cliente
- Políticas de retransmissão (caso sejam usadas)
- Funções de entidade (se utilizadas)
Para um mapeamento completo API a API, consulte a referência da API.
Alterações no espaço de nomes
// 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;
Alterações no atributo da função
// Before (In-Process)
[FunctionName("MyOrchestrator")]
// After (Isolated Worker)
[Function(nameof(MyOrchestrator))]
Alterações na função do orquestrador
Antes (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 };
}
Depois (Trabalhador Isolado):
[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 };
}
Diferenças principais
| Aspeto | Em Processo | Trabalhador Isolado |
|---|---|---|
| Tipo de contexto | IDurableOrchestrationContext |
TaskOrchestrationContext |
| Logger | parâmetro ILogger |
context.CreateReplaySafeLogger() |
| Attribute | [FunctionName] |
[Function] |
Alterações na função de atividade
Antes (In-Process):
[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;
}
Depois (Trabalhador Isolado):
[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;
}
Alterações nas funções do cliente
Antes (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);
}
Depois (Trabalhador Isolado):
[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);
}
Alterações no tipo de cliente
| Em andamento | Trabalhador isolado |
|---|---|
IDurableOrchestrationClient |
DurableTaskClient |
StartNewAsync() |
ScheduleNewOrchestrationInstanceAsync() |
CreateCheckStatusResponse() |
CreateCheckStatusResponseAsync() |
HttpRequest / IActionResult |
HttpRequestData / HttpResponseData |
Alterações na política de novas tentativas
O processo utiliza RetryOptions com CallActivityWithRetryAsync. O trabalhador isolado usa TaskOptions com o padrão CallActivityAsync.
Antes (In-Process):
var retryOptions = new RetryOptions(
firstRetryInterval: TimeSpan.FromSeconds(5),
maxNumberOfAttempts: 3);
string result = await context.CallActivityWithRetryAsync<string>(
"MyActivity", retryOptions, input);
Depois (Trabalhador Isolado):
var retryOptions = new TaskOptions(
new TaskRetryOptions(new RetryPolicy(
maxNumberOfAttempts: 3,
firstRetryInterval: TimeSpan.FromSeconds(5))));
string result = await context.CallActivityAsync<string>(
"MyActivity", input, retryOptions);
Alterações na função da entidade
Antes (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;
}
}
Depois (Trabalhador Isolado):
[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;
}
Alterações de comportamento disruptivas
Revise estas alterações antes de testar a sua aplicação migrada. Para o mapeamento completo API-a-API, consulte a referência da API.
Advertência
Alteração do padrão de serialização: O trabalhador isolado usa System.Text.Json por padrão em vez de Newtonsoft.Json. Se as suas orquestrações passarem por objetos complexos, teste a serialização cuidadosamente. Consulte diferenças de serialização JSON para opções de configuração.
Advertência
ContinueAsNew mudança padrão: O preserveUnprocessedEvents parâmetro padrão mudou de false (2.x) para true (isolado). Se a sua orquestração usar ContinueAsNew e depender de que eventos não processados sejam descartados, passe preserveUnprocessedEvents: false explicitamente.
Observação
Alteração do padrão RestartAsync: O restartWithNewInstanceId padrão do parâmetro mudou de true (2.x) para false (isolado). Se o seu código chamar RestartAsync e depender de ser gerado um novo ID de instância, passe explicitamente restartWithNewInstanceId: true.
Outras alterações notáveis:
-
Proxies de entidade removidos —
CreateEntityProxy<T>não está disponível. UseEntities.CallEntityAsyncouEntities.SignalEntityAsyncdiretamente. -
Operações de cross-task-hub removidas — Sobrecargas que aceitavam
taskHubName/connectionNamenão estão disponíveis. Apenas operações no mesmo centro de tarefas são suportadas. -
Histórico da orquestração transferido —
DurableOrchestrationStatus.Historyagora não está no objeto de estado. UtilizeDurableTaskClient.GetOrchestrationHistoryAsync.
Atualize o ficheiro local.settings.json
A mudança de chave é definir FUNCTIONS_WORKER_RUNTIME de dotnet para dotnet-isolated:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
}
}
Observação
A configuração do seu backend de armazenamento (Armazenamento do Azure, MSSQL, Netherite ou Durable Task Scheduler) mantém-se inalterada com a migração. Mantém as definições existentes relacionadas com o armazenamento.
Testar localmente
Executa a tua aplicação de funções localmente e verifica se todas as orquestrações, atividades e entidades funcionam corretamente.
func start
Verificar funcionalidade
Teste os seguintes cenários conforme aplicável:
- Inicie uma orquestração com um gatilho HTTP
- Monitorizar o estado da orquestração
- Verificar a ordem de execução da atividade
- Testar operações da entidade, se aplicável
- Verifique a telemetria do Application Insights
Publicar no Azure
Recomendado: Usar slots de implementação
Use slots de implementação para minimizar o tempo de inatividade.
- Cria um slot de preparação para a sua aplicação de função.
-
Atualizar configuração do slot de preparação:
- Defina
FUNCTIONS_WORKER_RUNTIMEcomodotnet-isolated. - Atualize a versão da pilha .NET se necessário.
- Defina
- Implementa o código migrado para o slot de staging.
- Teste cuidadosamente no slot de preparação.
- Realiza a troca de slot para transferir alterações para a produção.
Atualizar configurações do aplicativo
No portal Azure ou via CLI:
az functionapp config appsettings set \
--name <FUNCTION_APP_NAME> \
--resource-group <RESOURCE_GROUP> \
--settings FUNCTIONS_WORKER_RUNTIME=dotnet-isolated
Atualizar a configuração da pilha
Se pretender direcionar para uma versão diferente do .NET:
az functionapp config set \
--name <FUNCTION_APP_NAME> \
--resource-group <RESOURCE_GROUP> \
--net-framework-version v8.0
Problemas comuns de migração
Problema: Erros de carga de montagem
Sintoma:Could not load file or assembly erros.
Solução: Certifique-se de remover todas as referências de pacotes Microsoft.Azure.WebJobs.* e substituí-las por equivalentes de trabalhadores isolados.
Questão: Atributo de ligação não encontrado
Sintoma:The type or namespace 'QueueTrigger' could not be found
Solução: Adicione o pacote de extensão apropriado e atualize usando instruções:
// Add using statement
using Microsoft.Azure.Functions.Worker;
// Install package
// dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues
Problema: IDurableOrchestrationContext não encontrado
Sintoma:The type or namespace 'IDurableOrchestrationContext' could not be found
Solução: Substituir por TaskOrchestrationContext:
using Microsoft.DurableTask;
[Function(nameof(MyOrchestrator))]
public static async Task MyOrchestrator([OrchestrationTrigger] TaskOrchestrationContext context)
{
// ...
}
Questão: Diferenças na serialização JSON
Sintoma: Erros de serialização ou formatos de dados inesperados
Solução: O modelo isolado usa System.Text.Json por defeito. Configurar serialização em Program.cs:
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services => {
services.Configure<JsonSerializerOptions>(options => {
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
})
.Build();
Para usar Newtonsoft.Json em vez disso:
services.Configure<WorkerOptions>(options => {
options.Serializer = new NewtonsoftJsonObjectSerializer();
});
Problema: Migração de definições de serialização personalizadas
Sintoma: Usaste IMessageSerializerSettingsFactory no modelo em processo e precisas do equivalente no trabalhador isolado.
Solução: Configure o serializador do nível do trabalhador em Program.cs. Para detalhes, consulte a secção alterações comportamentais da referência da API e Serialização e persistência em Durable Functions.
Para usar Newtonsoft.Json com definições personalizadas:
// 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();
Observação
Esta abordagem requer os pacotes NuGet Newtonsoft.Json e Azure.Core.Serialization.
Lista de Verificação
Use esta lista de verificação para garantir uma migração completa:
- Ficheiro de projeto atualizado com
<OutputType>Exe</OutputType> - Substituíram
Microsoft.NET.Sdk.Functionspor pacotes de trabalhadores - Substituiu
Microsoft.Azure.WebJobs.Extensions.DurableTaskpor pacote isolado - Criado
Program.cscom a configuração do anfitrião - Classe removida
FunctionsStartup(se presente) - Atualizado tudo
[FunctionName]para[Function] - Substituído
IDurableOrchestrationContextporTaskOrchestrationContext - Substituído
IDurableOrchestrationClientporDurableTaskClient - Registo atualizado para usar DI ou
FunctionContext - Atualizado
local.settings.jsoncomdotnet-isolatedtempo de execução - Removi todas as instruções
Microsoft.Azure.WebJobs.*usando instruções - Adicionado
Microsoft.Azure.Functions.Workerusando declarações - Substituída
CreateEntityProxy<T>por chamadas diretasCallEntityAsync/SignalEntityAsync - Foram substituídas as sobrecargas de operação do hub entre tarefas (se usadas)
- Substituiu as chamadas de lote por-ID
GetStatusAsync/PurgeInstanceHistoryAsyncpor chamadas baseadas em filtro ou individuais - O acesso foi migrado de
DurableOrchestrationStatus.HistoryparaGetOrchestrationHistoryAsync - Atualizei os parâmetros do construtor de entidade
DispatchAsyncpara usar DI - Testava todas as funções localmente
- Implantado no slot de pré-produção e verificado
- Transferido para produção
Passos seguintes
- Mapeamento de API de processos em execução para agentes isolados — referência completa de API para a sua migração
- Visão geral das Durable Functions para .NET processo isolado
- Durable Functions versões e guia de migração
Conteúdo relacionado
- Guia oficial de migração Microsoft (todos os Funções do Azure)
- .NET visão geral do processo de trabalhador isolado
- Diferenças isoladas no modelo de trabalhador
- Serialização e persistência em Durable Functions
- implantação sem tempo de inatividade para Durable Functions
- Configurar o Agendador de Tarefas Durável