本指南將引導你如何將.NET Durable Functions應用程式從處理中模式遷移到隔離工作者模式。 進行中的模式 將於 2026 年 11 月 10 日結束支援。 超過該日期後,將不再提供安全更新或錯誤修正。 獨立工作者模型還提供完整的流程控制、標準的 .NET 相依性注入,以及使用最新平台功能。
Warning
目前進行中模式的支援將於 2026年11月10日結束。 我們建議現在就遷移。 關於孤立工人模型的背景,請參見 .NET 孤立工人流程概述。
遷徙檢查清單
請使用以下清單來追蹤你在每個遷移步驟中的進度:
| Step | 章節 |
|---|---|
| 1. 驗證先修條件 | Prerequisites |
| 2. 更新專案檔案 | 更新專案檔案 |
| 3. 加入Program.cs | 加入Program.cs |
| 4. 更新套件參考 | 更新套件參考 |
| 5. 更新功能程式碼 | 更新函式程式碼 |
| 6. 更新 local.settings.json | 更新 local.settings.json |
| 7. 本地測試 | 本地測試 |
| 8. 部署到 Azure | 部署至 Azure |
先決條件
- Azure Functions Core Tools v4.x 或更新版本
- .NET 8.0 SDK(或你的目標.NET版本)
- Visual Studio 2022 或 VS Code 搭配 Azure Functions 擴充功能
辨識可遷移的應用程式(可選)
如果你不確定哪些應用程式仍在使用進行中模式,請執行這個 Azure PowerShell 腳本:
$FunctionApps = Get-AzFunctionApp
$AppInfo = @{}
foreach ($App in $FunctionApps)
{
if ($App.Runtime -eq 'dotnet')
{
$AppInfo.Add($App.Name, $App.Runtime)
}
}
$AppInfo
顯示 dotnet 為執行時的應用程式則使用進行中模型。 顯示 dotnet-isolated 的應用程式已經使用隔離工作者模式。
更新專案檔案
之前(處理中)
<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>
之後(孤立工作者)
<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>
主要變更是切換為可執行輸出型態,並將所有 Microsoft.Azure.WebJobs.* 套件替換為其 Microsoft.Azure.Functions.Worker.* 等效套件。
加入Program.cs
孤立工人模型需要一個 Program.cs 切入點。 在你的專案根目錄中建立這個檔案。 如果你在 FunctionsStartup 中有 Startup.cs 類別,請將那些服務註冊移到 ConfigureServices 區塊裡,並刪除 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();
更新套件引用參考
Durable Functions 套件映射
| 內含式套件 | 隔離背景工作套件 |
|---|---|
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 |
常見擴充套件映射
| 處理中 | 孤立工人 |
|---|---|
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 |
Important
移除專案中對 Microsoft.Azure.WebJobs.* 命名空間和 Microsoft.Azure.Functions.Extensions 的引用。
更新函式程式碼
本節涵蓋每種 Durable Functions 類型的程式碼變更。 跳到你應用程式使用的功能類型區塊:
完整的 API 逐 API 映射,請參閱 API 參考文獻。
命名空間變更
// 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;
函數屬性變更
// Before (In-Process)
[FunctionName("MyOrchestrator")]
// After (Isolated Worker)
[Function(nameof(MyOrchestrator))]
協調器函式變更
之前(進行中):
[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 };
}
之後 (隔離背景工作):
[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 };
}
主要差異
| 層面 | 處理中 | 孤立工人 |
|---|---|---|
| 上下文類型 | IDurableOrchestrationContext |
TaskOrchestrationContext |
| Logger |
ILogger 參數 |
context.CreateReplaySafeLogger() |
| 屬性 | [FunctionName] |
[Function] |
活動函式變更
之前(進行中):
[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;
}
之後 (隔離背景工作):
[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;
}
用戶端功能變更
之前(進行中):
[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);
}
之後 (隔離背景工作):
[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);
}
用戶端類型的變更
| 處理中 | 孤立工人 |
|---|---|
IDurableOrchestrationClient |
DurableTaskClient |
StartNewAsync() |
ScheduleNewOrchestrationInstanceAsync() |
CreateCheckStatusResponse() |
CreateCheckStatusResponseAsync() |
HttpRequest / IActionResult |
HttpRequestData / HttpResponseData |
重試政策變更
進行中會使用 RetryOptions 和 CallActivityWithRetryAsync。 隔離背景工作會搭配標準 TaskOptions 使用 CallActivityAsync。
之前(進行中):
var retryOptions = new RetryOptions(
firstRetryInterval: TimeSpan.FromSeconds(5),
maxNumberOfAttempts: 3);
string result = await context.CallActivityWithRetryAsync<string>(
"MyActivity", retryOptions, input);
之後 (隔離背景工作):
var retryOptions = new TaskOptions(
new TaskRetryOptions(new RetryPolicy(
maxNumberOfAttempts: 3,
firstRetryInterval: TimeSpan.FromSeconds(5))));
string result = await context.CallActivityAsync<string>(
"MyActivity", input, retryOptions);
實體功能變更
之前(進行中):
[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;
}
}
之後 (隔離背景工作):
[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;
}
中斷性行為變更
在測試遷移的應用程式前,請先檢視這些變更。 完整的 API 逐 API 映射,請參閱 API 參考文獻。
Warning
序列化預設變更:孤立的工作者預設使用 System.Text.Json ,而非 Newtonsoft.Json。 如果你的編排程序需要傳遞複雜物件,請仔細測試序列化。 請參閱 JSON 序列化差異 以取得設定選項。
Warning
ContinueAsNew 預設值變更:將 preserveUnprocessedEvents 參數的預設值從 false (2.x) 改為 true (isolated)。 如果您的協調流程使用 ContinueAsNew,並依賴捨棄未處理事件,請明確傳遞 preserveUnprocessedEvents: false。
Note
RestartAsync 預設變更:參數 restartWithNewInstanceId 預設值從 true (2.x) 改為 false (孤立)。 如果你的程式碼呼叫 RestartAsync 並依賴於產生新的實例 ID,則明確傳遞 restartWithNewInstanceId: true。
其他顯著變動:
-
實體代理已移除 —
CreateEntityProxy<T>無法使用。 直接使用Entities.CallEntityAsync或Entities.SignalEntityAsync。 -
跨任務中樞操作已移除 — 接受的多載
taskHubName/connectionName已無法使用。 僅支援同任務中心操作。 -
編排歷史移動 —
DurableOrchestrationStatus.History不再出現在狀態物件上。 請使用DurableTaskClient.GetOrchestrationHistoryAsync。
更新 local.settings.json
鍵變更為將 FUNCTIONS_WORKER_RUNTIME 設定從 dotnet 為 dotnet-isolated:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
}
}
Note
你的儲存後端設定(Azure 儲存體、MSSQL、Netherite 或 Durable Task Scheduler)在遷移過程中沒有改變。 保留你現有的儲存相關設定。
本地測試
在本機執行您的函數應用程式,並確認所有協調流程、活動與實體皆正常運作。
func start
確認正常運作
請測試以下情境(視情況而定):
- 用 HTTP 觸發器開始編排
- 監控協調狀態
- 驗證活動執行順序
- 測試實體操作(如適用)
- 查看 Application Insights 遙測
部署至 Azure
建議:使用部署插槽
使用部署插槽來減少停機時間:
- 為你的 Function 應用程式建立一個暫存插槽。
-
更新暫存槽配置:
- 將
FUNCTIONS_WORKER_RUNTIME設定為dotnet-isolated。 - 如果需要,更新 .NET 堆疊版本。
- 將
- 將已移轉的程式碼部署至預備位置。
- 在預備位置中完整測試。
- 執行位置交換,將變更移至生產環境。
更新應用程式設定
在 Azure 入口網站或透過 CLI 進行:
az functionapp config appsettings set \
--name <FUNCTION_APP_NAME> \
--resource-group <RESOURCE_GROUP> \
--settings FUNCTIONS_WORKER_RUNTIME=dotnet-isolated
更新堆疊設定
如果針對不同的 .NET 版本:
az functionapp config set \
--name <FUNCTION_APP_NAME> \
--resource-group <RESOURCE_GROUP> \
--net-framework-version v8.0
常見移轉問題
問題:組件載入錯誤
症狀:Could not load file or assembly 錯誤。
解決方法:請確保移除所有 Microsoft.Azure.WebJobs.* 套件參考,並以隔離背景工作的對應套件取代。
問題:未找到綁定屬性
症狀:The type or namespace 'QueueTrigger' could not be found
解決方案: 新增適當的擴充套件並使用語句更新:
// Add using statement
using Microsoft.Azure.Functions.Worker;
// Install package
// dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues
問題:IDurableOrchestrationContext 找不到
症狀:The type or namespace 'IDurableOrchestrationContext' could not be found
解決方案: 替換為 TaskOrchestrationContext:
using Microsoft.DurableTask;
[Function(nameof(MyOrchestrator))]
public static async Task MyOrchestrator([OrchestrationTrigger] TaskOrchestrationContext context)
{
// ...
}
問題:JSON 序列化差異
症狀: 序列化錯誤或意外資料格式
解決方案:孤立模型預設使用System.Text.Json 在Program.cs中設定序列化:
var host = new HostBuilder()
.ConfigureFunctionsWebApplication()
.ConfigureServices(services => {
services.Configure<JsonSerializerOptions>(options => {
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});
})
.Build();
改用 Newtonsoft.Json:
services.Configure<WorkerOptions>(options => {
options.Serializer = new NewtonsoftJsonObjectSerializer();
});
問題:遷移自訂序列化設定
症狀:您在同處理序模型中使用了IMessageSerializerSettingsFactory,並需要在隔離式背景工作角色中尋找對應功能。
解決方案:在 Program.cs 中設定工作層級序列化器。 詳情請參閱 API 參考文獻中的 行為變更部分 以及 Durable Functions 中的 序列化與持久性。
要使用 Newtonsoft.Json 並進行自訂化設定:
// 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();
Note
此方法需要 Newtonsoft.Json 與 Azure.Core.Serialization NuGet 套件。
檢查清單
請使用這份清單確保完整的遷移:
- 已使用
<OutputType>Exe</OutputType>更新專案檔 - 以工作套件取代
Microsoft.NET.Sdk.Functions - 用隔離封裝取代了
Microsoft.Azure.WebJobs.Extensions.DurableTask - 已建立含主機組態的
Program.cs - 移除
FunctionsStartup類別(如有) - 全部更新
[FunctionName]為[Function] -
IDurableOrchestrationContext被TaskOrchestrationContext取代 -
IDurableOrchestrationClient被DurableTaskClient取代 - 更新日誌以使用 DI 或
FunctionContext - 已使用
local.settings.json執行階段更新dotnet-isolated - 已移除所有
Microsoft.Azure.WebJobs.*using 陳述式 - 已新增
Microsoft.Azure.Functions.Workerusing 陳述式 - 已將
CreateEntityProxy<T>替換為直接呼叫CallEntityAsync/SignalEntityAsync - 替換跨任務集線器運算過載(如果有使用)
- 已將依 ID 的批次
GetStatusAsync/PurgeInstanceHistoryAsync呼叫,替換為以篩選為基礎或個別的呼叫 - 已將對
DurableOrchestrationStatus.History的存取移轉為GetOrchestrationHistoryAsync - 已更新實體
DispatchAsync建構函式參數,以使用 DI - 所有函數都本地測試過
- 已部署至預備位置並完成驗證
- 已交換到生產環境
下一步
- 進程內遷移到獨立工作角色的 API 對應 — 適用於您移轉的完整 API 參考資料
- 適用於 .NET 隔離背景工作的 Durable Functions 概觀
- Durable Functions版本與遷移指南