📌پیادهسازی اصولی لغو عملیات (Cancellation Support) در تمام لایههای داتنت
نادیده گرفتن الگوی لغو عملیات یکی از شایعترین نقصها در پروژههای داتنت است. هنگامی که کاربری تب مرورگر را میبندد یا کلاینت درخواست HTTP را متوقف میکند، در صورت عدم انتشار توکن لغو (
CancellationToken)، سرور همچنان به اجرای کوئریهای سنگین دیتابیس، پردازشهای CPU و فراخوانیهای I/O ادامه میدهد که نتیجه آن هدررفت مستقیم منابع و اشباع Thread Pool است. استفاده از Copilot برای افزودن قابلیت Cancellation نباید به «لغو ظاهری یا نمادین» (Fake Cancellation) با چک کردن دستی توکن منتهی شود، بلکه باید انتشار پیوسته و معنادار توکن در تمام لایهها تا پایینترین سطح I/O را پیادهسازی کند.کالبدشکافی لغو نامعتبر در برابر لغو واقعی
رویکرد اشتباه (لغو ظاهری): قرار دادن متوالی
cancellationToken.ThrowIfCancellationRequested() در متدها، بدون ارسال توکن به عملیات پایهای دیتابیس یا سوکت شبکه. در این حالت، تا زمانی که کوئری دیتابیس تمام نشود، برنامه متوجه توقف درخواست نمیشود.رویکرد اصولی (لغو واقعی در سطح سختافزار/درایور): ارسال توکن به درایور دیتابیس (مانند Npgsql یا Microsoft.Data.SqlClient) تا به محض لغو درخواست کلاینت، دستور
ATTN یا لغو سوکت به سرور دیتابیس فرستاده شده و پردازش همانجا متوقف شود.ساختار پرامپت مهندسی برای ردیابی و افزودن CancellationToken
برای گسترش ایمن توکن لغو در لایههای معماری:
ساختار لغو عملیات (CancellationToken) را در تمام زنجیره این سناریو از لایه Controller تا پایگاه داده پیادهسازی کن.
الزامات و محورهای ردیابی:
1️⃣دریافت توکن از درخواست HTTP کلاینت در لایه اکشن کنترلر / Minimal API.
2️⃣انتقال مستقیم توکن از طریق Interfaceهای لایه سرویس و ریپازیتوری.
3️⃣اعمال مستقیم توکن روی درایور و متدهای ناهمگام EF Core (مانند ToListAsyncیا SaveChangesAsync)
4️⃣پرهیز از لغو ظاهری (Fake Cancellation) و توضیح دقیق نقطهای که لغو به صورت فیزیکی عملیات I/O را قطع میکند.
5️⃣مدیریت تمیز استثنای OperationCanceledException بدون لاگهای خطای بحرانی نامرتبط.
ردیابی گامبهگام در لایههای مختلف معماری داتنت
۱. لایه Controller / Presentation
کنترلر فریمورک ASP.NET Core به طور خودکار
HttpContext.RequestAborted را به پارامترهای از نوع CancellationToken متصل (Bind) میکند:[HttpGet]
public async Task<ActionResult<IReadOnlyList<OrderResponseDto>>> GetOrdersAsync(
CancellationToken cancellationToken)
{
var orders = await orderService.GetOrdersAsync(cancellationToken);
return Ok(orders);
}
۲. لایه Service و Repository
توکن باید بدون دستکاری و ایجاد State اضافی از امضای متدها عبور کند:
public interface IOrderRepository
{
Task<IReadOnlyList<Order>> GetOrdersAsync(CancellationToken cancellationToken);
}
public sealed class OrderRepository(ApplicationDbContext dbContext) : IOrderRepository
{
public async Task<IReadOnlyList<Order>> GetOrdersAsync(CancellationToken cancellationToken)
{
// نقطه اثر واقعی: توکن به صورت مستقیم به درایور پایگاه داده فرستاده میشود
return await dbContext.Orders
.AsNoTracking()
.ToListAsync(cancellationToken);
}
}
نکات تکمیلی برای سناریوهای پیشرفته لغو عملیات
ترکیب توکنها با
CancellationTokenSource.CreateLinkedTokenSource: در پردازشهای پسزمینه یا فراخوانی وبسرویسها، گاهی نیاز به اعمال Timeout مشخص در کنار درخواست توقف کاربر وجود دارد:using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);
await externalClient.FetchDataAsync(linkedCts.Token);
مدیریت لاگها در زمان لغو: استثنای
OperationCanceledException یا TaskCanceledException یک رفتار طبیعی و مورد انتظار است، نه یک باگ غیرمنتظره (Crash). به Copilot تأکید کنید که هنگام مدیریت خطا در Middlewareها، لغو درخواست را به عنوان خطای سطحی (LogInformation یا LogDebug) لاگ کند، نه به عنوان خطای بحرانی سطح LogError.عملیات بحرانی غیرقابل لغو: در تراکنشهای مالی یا ثبت لاگهای حساس که پس از شروع نباید متوقف شوند، از
CancellationToken.None استفاده کنید تا لغو سمت کاربر باعث ناتمام ماندن ثبت اسناد نشود.قاعده کلیدی: انتشار توکن لغو باید پیوسته و بدون وقفه باشد؛ هدف لغو عملیات، آزادسازی فوری سوکتها، اتصالات دیتابیس و منابع سختافزاری در پایینترین لایه I/O است.