إشعار
يتطلب الوصول إلى هذه الصفحة تخويلاً. يمكنك محاولة تسجيل الدخول أو تغيير الدلائل.
يتطلب الوصول إلى هذه الصفحة تخويلاً. يمكنك محاولة تغيير الدلائل.
يرشدك هذا الدليل خلال نقل تطبيق .NET Durable Functions من نموذج العملية إلى نموذج العامل المعزول. يصل النموذج قيد التشغيل إلى نهاية الدعم في 10 نوفمبر 2026. بعد ذلك التاريخ، لا يتم توفير تحديثات أمنية أو إصلاحات للأخطاء. نموذج العامل المعزول يمنحك أيضا تحكما كاملا في العمليات، وحقن اعتماد .NET القياسي، والوصول إلى أحدث ميزات المنصة.
تحذير
ينتهي دعم النموذج قيد التنفيذ في 10 نوفمبر 2026. نوصي بالانتقال الآن. للحصول على خلفية حول نموذج العامل المعزول، انظر .NET نظرة عامة على عملية العامل المعزول.
قائمة التحقق من الترحيل
استخدم القائمة التالية لتتبع تقدمك في كل خطوة ترحيل:
| خطوة | قسم |
|---|---|
| 1. التحقق من المتطلبات المسبقة | المتطلبات الأساسية |
| 2. تحديث ملف المشروع | تحديث ملف المشروع |
| 3. أضف Program.cs | أضف Program.cs |
| 4. تحديث مراجع الحزم | تحديث مراجع الحزم |
| 5. تحديث كود الدالة | تحديث كود الدالة |
| 6. تحديث local.settings.json | تحديث local.settings.json |
| 7. اختبار محلي | اختبار محلي |
| 8. النشر إلى Azure | النشر على Azure |
المتطلبات المسبقه
- دالات Azure Core Tools v4.x أو أحدث
- .NET 8.0 SDK (أو النسخة المستهدفة .NET لديك)
- Visual Studio 2022 أو VS Code مع دالات Azure الامتداد
تحديد التطبيقات التي يجب نقلها (اختياري)
إذا لم تكن متأكدا من التطبيقات التي لا تزال تستخدم نموذج العملية، قم بتشغيل سكريبت 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 |
مهم
قم بإزالة أي مراجع إلى Microsoft.Azure.WebJobs.* وMicrosoft.Azure.Functions.Extensions من مشروعك.
تحديث كود الدالة
يغطي هذا القسم تغييرات الكود لكل نوع من Durable Functions. انتقل إلى قسم أنواع الوظائف التي يستخدمها تطبيقك:
- تغييرات مساحة الأسماء
- وظائف الموزع
- وظائف النشاط
- وظائف العميل
- سياسات إعادة المحاولة (إذا تم استخدامها)
- دوال الكيان (إذا استخدم)
للحصول على تعيين 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))]
تغييرات وظيفة الأوركستراتور
قبل (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 };
}
بعد (عامل معزول):
[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 };
}
الاختلافات الرئيسية
| الجانب | In-Process | عامل معزول |
|---|---|---|
| نوع السياق | IDurableOrchestrationContext |
TaskOrchestrationContext |
| Logger |
ILogger المعامل |
context.CreateReplaySafeLogger() |
| السمة | [FunctionName] |
[Function] |
تغيرات دالة النشاط
قبل (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;
}
بعد (عامل معزول):
[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;
}
تغييرات وظيفة العميل
قبل (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);
}
بعد (عامل معزول):
[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.
قبل (In-Process):
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);
تغييرات دالة الكيان
قبل (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;
}
}
بعد (عامل معزول):
[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).
تحذير
تم تغيير الإعداد السريعي: العامل المعزول يستخدم System.Text.Json بشكل افتراضي بدلا من Newtonsoft.Json. إذا كانت التوزيع الموسيقي لديك تمر بأشياء معقدة، اختبر التسلسل بعناية. انظر اختلافات تسلسل JSON لخيارات التكوين.
تحذير
تغيير الإعداد الافتراضي ContinueAsNew: تغير الإعداد preserveUnprocessedEvents الافتراضي للمعلمة من false (2.x) إلى true (معزول). إذا كان تنسيقك يستخدم ContinueAsNew ويعتمد على التخلص من أحداث غير معالجة، فرفض preserveUnprocessedEvents: falseبشكل صريح .
ملاحظة
تغيير الإعداد الافتراضي RestartAsync: تغير الوضع restartWithNewInstanceId الافتراضي للمعلمات من true (2.x) إلى false (معزول). إذا كان كودك يستدعي RestartAsync ويعتمد على معرف مثيل جديد يتم توليده، قم بتمرير 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"
}
}
ملاحظة
تكوين التخزين الخلفي (تخزين Azure، MSSQL، Netherite، أو Durable Task Scheduler) لم يتغير بسبب الترحيل. احتفظ بإعدادات التخزين الحالية لديك.
اختبر بشكل محلي
شغل تطبيق الوظائف محليا وتحقق من أن جميع التنسيقات والأنشطة والكيانات تعمل بشكل صحيح.
func start
التحقق من الوظائف
اختبر السيناريوهات التالية حسب الاقتضاء:
- ابدأ التوزيع الأوركسترالي باستخدام مشغل HTTP
- مراقبة حالة التوزيع الموسيقي
- تحقق من ترتيب تنفيذ النشاط
- عمليات الكيانات المختبرة إذا كان ذلك ممكنا
- تحقق من بيانات Application Insights
النشر إلى Azure
موصى به: استخدم فتحات النشر
استخدم فتحات النشر لتقليل وقت التوقف:
- أنشئ فتحة تجهيز لتطبيق الوظيفة الخاص بك.
-
تحديث إعدادات فتحة التجريب:
- ضبطه
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 أخطاء.
Solution: تأكد من إزالة جميع مراجع حزمة 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
المشكلة: IDurableOrchestrationالسياق غير موجود
عَرَض: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. للتفاصيل، راجع قسم behavioral changes في مرجع واجهة برمجة التطبيقات وتسلسل واستمرارية في 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();
ملاحظة
يتطلب هذا النهج حزم NuGet Newtonsoft.Json و Azure.Core.Serialization.
قائمة تحقق
استخدم هذه القائمة لضمان الانتقال الكامل:
- ملف المشروع المحدث مع
<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.*باستخدام العبارات - تمت إضافة
Microsoft.Azure.Functions.Workerباستخدام العبارات - تم استبداله
CreateEntityProxy<T>بمكالمات مباشرةCallEntityAsync/SignalEntityAsync - استبدال التحميل الزائد لتشغيل محور المهام (إذا تم استخدامه)
- استبدلت استدعاءات by-ID الدفعية
GetStatusAsync/PurgeInstanceHistoryAsyncبالاستدعاءات القائمة على المرشح أو الفردية - الوصول المهاجر
DurableOrchestrationStatus.HistoryإلىGetOrchestrationHistoryAsync - تحديث معايير بناء الكيانات
DispatchAsyncلاستخدام DI - اختبرت جميع الدوال محليا
- تم نشره في موضع التجهيز والتحقق منه
- تم التحويل إلى الإنتاج
الخطوات التالية
- تعيين واجهة برمجة التطبيقات أثناء العملية إلى عامل معزول — مرجع API كامل لترحيلك
- Durable Functions نظرة عامة .NET العامل المعزول
- Durable Functions الإصدارات ودليل الهجرة