Migrera din Durable Functions-app från in-process till isolerad arbetarmodell (.NET)

Den här guiden vägleder dig genom att migrera din .NET Durable Functions-app från den pågående modellen till den isolerade arbetsmodellen. Den pågående modellen når slutet av supporten den 10 november 2026. Efter det datumet tillhandahålls inga säkerhetsuppdateringar eller felkorrigeringar. Den isolerade arbetsmodellen ger dig också fullständig processkontroll, standard .NET beroendeinjektion och tillgång till de senaste plattformsfunktionerna.

Varning

Stödet för den processbaserade modellen upphör den 10 november 2026. Vi rekommenderar att du migrerar nu. Bakgrund om den isolerade arbetsmodellen finns i .NET översikt över isolerade arbetsprocesser.

Checklista för migrering

Använd följande checklista för att spåra förloppet genom varje migreringssteg:

Steg Avsnitt
1. Kontrollera kraven Prerequisites
2. Uppdatera projektfilen Uppdatera projektfilen
3. Lägg till Program.cs Lägg till Program.cs
4. Uppdatera paketreferenser Uppdatera paketreferenser
5. Uppdatera funktionskoden Uppdatera funktionskod
6. Uppdatera local.settings.json Uppdatera local.settings.json
7. Testa lokalt Testa lokalt
8. Distribuera till Azure Distribuera till Azure

Förutsättningar

  • Azure Functions Core Tools v4.x eller senare
  • .NET 8.0 SDK (eller din målversion av .NET)
  • Visual Studio 2022 eller VS Code med Azure Functions-tillägget

Identifiera appar som ska migreras (valfritt)

Om du inte är säker på vilka appar som fortfarande använder den pågående modellen kör du det här Azure PowerShell skriptet:

$FunctionApps = Get-AzFunctionApp

$AppInfo = @{}

foreach ($App in $FunctionApps)
{
     if ($App.Runtime -eq 'dotnet')
     {
          $AppInfo.Add($App.Name, $App.Runtime)
     }
}

$AppInfo

Appar som visar dotnet som körning använder in process-modellen. Appar som visar dotnet-isolated använder redan den isolerade arbetsmodellen.

Uppdatera projektfilen

Före (i bearbetning)

<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>

Efter (isolerad arbetare)

<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>

De viktigaste ändringarna växlar till en körbar utdatatyp och ersätter alla Microsoft.Azure.WebJobs.*-paket med deras Microsoft.Azure.Functions.Worker.* motsvarigheter.

Lägg till Program.cs

Den isolerade arbetsmodellen kräver en Program.cs startpunkt. Skapa den här filen i projektroten. Om du har en FunctionsStartup klass i Startup.csflyttar du dessa tjänstregistreringar till ConfigureServices blocket och tar bort 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();

Uppdatera paketreferenser

Durable Functions för kartläggning av paket

Pågående processpaket Isolerat arbetarpaket
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

Gemensam paketmappning för tillägg

Pågående Isolerad arbetare
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

Viktigt!

Ta bort referenser till Microsoft.Azure.WebJobs.*-namnområden och Microsoft.Azure.Functions.Extensions från projektet.

Uppdatera funktionskod

Det här avsnittet beskriver kodändringarna för varje Durable Functions typ. Gå till avsnittet för de funktionstyper som appen använder:

En fullständig API-by-API-mappning finns i API-referensen.

Namnrymmesändringar

// 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;

Funktionsattributändringar

// Before (In-Process)
[FunctionName("MyOrchestrator")]

// After (Isolated Worker)
[Function(nameof(MyOrchestrator))]

Orchestrator-funktionsändringar

Före (Under behandling):

[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 };
}

Efter (Isolerad arbetare):

[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 };
}

Viktiga skillnader

Aspekt I processen Isolerad arbetare
Kontexttyp IDurableOrchestrationContext TaskOrchestrationContext
Loggverktyg ILogger-parametern context.CreateReplaySafeLogger()
Attribute [FunctionName] [Function]

Ändringar i aktivitetsfunktionen

Före (Under behandling):

[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;
}

Efter (Isolerad arbetare):

[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;
}

Ändringar i klientfunktionen

Före (Under behandling):

[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);
}

Efter (Isolerad arbetare):

[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);
}

Ändringar av klienttyp

Pågående Isolerad arbetare
IDurableOrchestrationClient DurableTaskClient
StartNewAsync() ScheduleNewOrchestrationInstanceAsync()
CreateCheckStatusResponse() CreateCheckStatusResponseAsync()
HttpRequest / IActionResult HttpRequestData / HttpResponseData

Ändringar i återförsökspolicy

In-process använder RetryOptions med CallActivityWithRetryAsync. Den isolerade arbetaren använder TaskOptions med standarden CallActivityAsync.

Före (Under behandling):

var retryOptions = new RetryOptions(
    firstRetryInterval: TimeSpan.FromSeconds(5),
    maxNumberOfAttempts: 3);

string result = await context.CallActivityWithRetryAsync<string>(
    "MyActivity", retryOptions, input);

Efter (Isolerad arbetare):

var retryOptions = new TaskOptions(
    new TaskRetryOptions(new RetryPolicy(
        maxNumberOfAttempts: 3,
        firstRetryInterval: TimeSpan.FromSeconds(5))));

string result = await context.CallActivityAsync<string>(
    "MyActivity", input, retryOptions);

Ändringar i entitetsfunktionen

Före (Under behandling):

[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;
    }
}

Efter (Isolerad arbetare):

[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;
}

Brytande beteendeändringar

Granska dessa ändringar innan du testar din migrerade app. Fullständig API-efter-API-mappning finns i API-referensen.

Varning

Standard för serialisering har ändrats: Den isolerade arbetaren använder System.Text.Json som standard i stället Newtonsoft.Jsonför . Om dina orkestreringar skickar komplexa objekt bör du testa serialiseringen noggrant. Se JSON-serialiseringsskillnader för konfigurationsalternativ.

Varning

ContinueAsNy standardändring: Standardinställningen för parametern preserveUnprocessedEvents har ändrats från false (2.x) till true (isolerad). Om din orkestrering använder ContinueAsNew och förlitar sig på att obearbetade händelser kastas bort, skicka preserveUnprocessedEvents: false uttryckligen.

Anmärkning

RestartAsync standardändring: Standardinställningen för parametern restartWithNewInstanceId har ändrats från true (2.x) till false (isolerad). Om koden anropar RestartAsync och är beroende av att ett nytt instans-ID genereras, skickar du uttryckligen restartWithNewInstanceId: true.

Andra viktiga ändringar:

  • Entitetsproxyn har tagits bortCreateEntityProxy<T> är inte tillgänglig. Använd Entities.CallEntityAsync eller Entities.SignalEntityAsync direkt.
  • Operationer mellan uppgiftshubbar har tagits bort – Överbelastningar som accepterade taskHubName/connectionName är inte tillgängliga. Endast operationer med samma task-hubb stöds.
  • Orkestreringshistorik har flyttatsDurableOrchestrationStatus.History finns inte längre i statusobjektet. Använd DurableTaskClient.GetOrchestrationHistoryAsync.

Uppdatera local.settings.json

Nyckeländringen är inställningen FUNCTIONS_WORKER_RUNTIME från dotnet till dotnet-isolated:

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
    }
}

Anmärkning

Konfigurationen av lagringsserverdelen (Azure Storage, MSSQL, Netherite eller Durable Task Scheduler) ändras inte av migreringen. Behåll dina befintliga lagringsrelaterade inställningar.

Testa lokalt

Kör funktionsappen lokalt och kontrollera att alla orkestreringar, aktiviteter och entiteter fungerar korrekt.

func start

Verifiera funktioner

Testa följande scenarier efter behov:

  1. Starta en orkestrering med en HTTP-utlösare
  2. Övervaka orkestreringsstatusen
  3. Verifiera aktivitetskörningssekvensen
  4. Testa entitetsåtgärder om det är tillämpligt
  5. Kontrollera Application Insights-telemetri

Distribuera till Azure

Använd distributionsplatser för att minimera driftstopp:

  1. Skapa ett mellanlagringsfack för funktionsappen.
  2. Uppdatera konfigurationen av mellanlagringsplatsen:
    • Ställ in FUNCTIONS_WORKER_RUNTIMEdotnet-isolated.
    • Uppdatera .NET stackversion om det behövs.
  3. Distribuera migrerad kod till mellanlagringsplatsen.
  4. Testa noggrant i staging-miljön.
  5. Utför slotswap för att flytta ändringar till produktion.

Uppdatera programinställningar

I Azure-portalen eller via CLI:

az functionapp config appsettings set \
    --name <FUNCTION_APP_NAME> \
    --resource-group <RESOURCE_GROUP> \
    --settings FUNCTIONS_WORKER_RUNTIME=dotnet-isolated

Uppdatera stackkonfiguration

Om du riktar in dig på en annan .NET version:

az functionapp config set \
    --name <FUNCTION_APP_NAME> \
    --resource-group <RESOURCE_GROUP> \
    --net-framework-version v8.0

Vanliga migreringsproblem

Problem: Sammansättningsbelastningsfel

Symptom:Could not load file or assembly Fel.

Solution: Se till att ta bort alla Microsoft.Azure.WebJobs.* paketreferenser och ersätt dem med isolerade arbetsekvivalenter.

Problem: Det går inte att hitta bindningsattributet

Symptom:The type or namespace 'QueueTrigger' could not be found

Lösning: Lägg till lämpligt tilläggspaket och uppdatera med hjälp av instruktioner:

// Add using statement
using Microsoft.Azure.Functions.Worker;

// Install package
// dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues

Problem: IDurableOrchestrationContext hittades inte

Symptom:The type or namespace 'IDurableOrchestrationContext' could not be found

Lösning: Ersätt med TaskOrchestrationContext:

using Microsoft.DurableTask;

[Function(nameof(MyOrchestrator))]
public static async Task MyOrchestrator([OrchestrationTrigger] TaskOrchestrationContext context)
{
    // ...
}

Problem med JSON-serialiseringsskillnader

Symptom: Serialiseringsfel eller oväntade dataformat

Lösning: Den isolerade modellen använder System.Text.Json som standard. Konfigurera serialisering i Program.cs:

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureServices(services => {
        services.Configure<JsonSerializerOptions>(options => {
            options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
        });
    })
    .Build();

Så här använder du Newtonsoft.Json i stället:

services.Configure<WorkerOptions>(options => {
    options.Serializer = new NewtonsoftJsonObjectSerializer();
});

Problem: Migrera anpassade serialiseringsinställningar

Symptom: Du använde IMessageSerializerSettingsFactory i in-process-modellen och behöver motsvarande i en isolerad arbetarmiljö.

Lösning: Konfigurera serialiseraren på arbetsnivå i Program.cs. Mer information finns i avsnittet behavioral changes för API-referensen och Serialization and persistence in Durable Functions.

Så här använder du Newtonsoft.Json med anpassade inställningar:

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

Anmärkning

Den här metoden kräver nuget-paketen Newtonsoft.Json och Azure.Core.Serialization.

Checklista

Använd den här checklistan för att säkerställa en fullständig migrering:

  • Projektfilen har uppdaterats med <OutputType>Exe</OutputType>
  • Ersatte Microsoft.NET.Sdk.Functions med arbetspaket
  • Ersatte Microsoft.Azure.WebJobs.Extensions.DurableTask med isolerat paket
  • Skapad Program.cs med värdkonfiguration
  • Klassen har tagits bort FunctionsStartup (om den finns)
  • Alla [FunctionName] har uppdaterats till [Function]
  • Ersatt IDurableOrchestrationContext med TaskOrchestrationContext
  • Ersatt IDurableOrchestrationClient med DurableTaskClient
  • Loggning har uppdaterats för användning av DI eller FunctionContext
  • Uppdaterad local.settings.json med dotnet-isolated körtid
  • Alla Microsoft.Azure.WebJobs.* using-satser har tagits bort
  • Lade till Microsoft.Azure.Functions.Worker med hjälp av instruktioner
  • Ersatt CreateEntityProxy<T> med direktanrop CallEntityAsync/SignalEntityAsync
  • Ersatte överlagringar av åtgärder mellan uppgiftshubbar (om de används)
  • Ersatte batch GetStatusAsync/PurgeInstanceHistoryAsync ID-baserade anrop med filterbaserade eller enskilda anrop
  • Migrerad DurableOrchestrationStatus.History åtkomst till GetOrchestrationHistoryAsync
  • Uppdaterade entitetskonstruktorparamer DispatchAsync för att använda DI
  • Testade alla funktioner lokalt
  • Distribuerad till mellanlagringsplats och verifierad
  • Flyttad till produktion

Nästa steg