Migrating Durable Functions to .NET 8 Isolated
Anthony Giretti documents the migration of Azure Durable Functions from .NET 6 in-process to .NET 8 isolated, based on a real migration project. Non-Durable Functions moved easily; Durable Functions did not, and the post walks through every API that changed shape: the project file, the NuGet packages, and the four building blocks of the Durable Functions programming model (activities, entities, orchestrators, clients).
The core pattern across all four blocks is the same: WebJobs-namespaced packages and interfaces (IDurableOrchestrationContext, IDurableEntityContext, IDurableOrchestrationClient) give way to Worker-namespaced replacements (TaskOrchestrationContext, TaskEntityDispatcher, DurableTaskClient), and the generic GetInput<T>() call disappears in favor of typing the input directly as a function parameter.
Fichamento#
- The
.csprojneedsTargetFrameworkset tonet8.0,AzureFunctionsVersiontov4, andOutputTypetoExefor isolated mode to run at all. - A “Function already exists” crash is fixed by adding
<FunctionsEnableWorkerIndexing>False</FunctionsEnableWorkerIndexing>to the csproj. - Every NuGet package under
Microsoft.Azure.WebJobs.*gets replaced by itsMicrosoft.Azure.Functions.Worker.*equivalent;Microsoft.Azure.Functions.Worker.Sdk,.Extensions, and.Workeritself are required additions for isolated mode. local.settings.jsonneedsFUNCTIONS_WORKER_RUNTIMEchanged fromdotnettodotnet-isolated.Startup.csis replaced by aProgram.csbuilt aroundHostBuilder, with Application Insights wired throughAddApplicationInsightsTelemetryWorkerService()andConfigureFunctionsApplicationInsights(); a specific logging-rule removal is needed at the end of the chain to avoid a known custom-logging issue (linked to an open Azure SDK GitHub issue).- Activity functions:
[FunctionName]becomes[Function],IDurableActivityContextand itsGetInput<T>()call disappear, and the typed input becomes the method parameter directly. An activity with no input takes aFunctionContextparameter instead. - Entity functions:
IDurableEntityContextis replaced byTaskEntityDispatcher, keeping the sameDispatchAsync<T>()call. - Orchestrator functions see the widest set of changes:
IDurableOrchestrationContextbecomesTaskOrchestrationContext;context.LockAsync()becomesawait using (await context.Entities.LockEntitiesAsync());CallActivityWithRetryAsyncis replaced by a singleCallActivityAsyncoverload that takes retry options viaTaskOptions.FromRetryPolicy(new RetryPolicy(...)), with parameters and options in reversed order from the old signature; andcontext.SetOutput()is gone, replaced by changing the method’s return type toTask<string>and returning the value directly. - Durable clients:
IDurableOrchestrationClientbecomesDurableTaskClient, andStartNewAsync()becomesScheduleNewOrchestrationInstanceAsync().
