TGViewer
C# Geeks (.NET) C# Geeks (.NET) @csharpgeeks · 549 subscribers
Post #325 156
🛠 پیاده‌سازی هم‌توانی (Idempotency) در ASP.NET Core


برای پیاده‌سازی هم‌توانی، از یک استراتژی شامل کلیدهای هم‌توانی (Idempotency Keys) استفاده خواهیم کرد: 🔑

🔹️کلاینت یک کلید یکتای Guid برای هر عملیات تولید کرده و آن را در هدر سفارشی ارسال می‌کند.

🔹️سرور بررسی می‌کند که آیا این کلید را قبلاً دیده است:

🔹️برای یک کلید جدید، درخواست را پردازش کرده و نتیجه را ذخیره می‌کند.

🔹️برای یک کلید شناخته شده، نتیجه ذخیره شده را بدون پردازش مجدد برمی‌گرداند.

این مکانیسم تضمین می‌کند که درخواست‌های تکراری (مثلاً به دلیل خطاهای شبکه) فقط یک بار در سرور پردازش شوند. 🛡

💫 ترکیب Attribute و IAsyncActionFilter

ما می‌توانیم هم‌توانی را برای متدهای کنترلر با ترکیب یک Attribute و IAsyncActionFilter پیاده‌سازی کنیم. با این کار، می‌توانیم IdempotentAttribute را به سادگی برای اعمال هم‌توانی به یک اِندپوینت مشخص کنیم.

نکته مهم در مورد شکست: ⚠️ وقتی یک درخواست شکست می‌خورد (کد وضعیت 4xx/5xx برمی‌گرداند)، ما پاسخ را کش (Cache) نمی‌کنیم. این به کلاینت‌ها اجازه می‌دهد تا با همان کلید هم‌توانی دوباره تلاش کنند. با این حال، باید در نظر داشت که این رفتار به این معنی است که یک درخواست شکست‌خورده که با یک درخواست موفق (با همان کلید) دنبال شود، موفق خواهد شد. حتماً بررسی کنید که این رفتار با الزامات کسب و کار شما هماهنگ باشد.

📜 کد: IdempotentAttribute و منطق کشینگ

در اینجا منطق اصلی فیلتر اکشن ما آمده است:
[AttributeUsage(AttributeTargets.Method)]
internal sealed class IdempotentAttribute : Attribute, IAsyncActionFilter
{
private const int DefaultCacheTimeInMinutes = 60;
private readonly TimeSpan _cacheDuration;

public IdempotentAttribute(int cacheTimeInMinutes = DefaultCacheTimeInMinutes)
{
_cacheDuration = TimeSpan.FromMinutes(cacheTimeInMinutes);
}

public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
// Parse the Idempotence-Key header from the request
if (!context.HttpContext.Request.Headers.TryGetValue(
"Idempotence-Key",
out StringValues idempotenceKeyValue) ||
!Guid.TryParse(idempotenceKeyValue, out Guid idempotenceKey))
{
context.Result = new BadRequestObjectResult("Invalid or missing Idempotence-Key header");
return;
}

IDistributedCache cache = context.HttpContext
.RequestServices.GetRequiredService<IDistributedCache>();

// Check if we already processed this request and return a cached response (if it exists)
string cacheKey = $"Idempotent_{idempotenceKey}";
string? cachedResult = await cache.GetStringAsync(cacheKey);
if (cachedResult is not null)
{
IdempotentResponse response = JsonSerializer.Deserialize<IdempotentResponse>(cachedResult)!;

var result = new ObjectResult(response.Value) { StatusCode = response.StatusCode };
context.Result = result;

return;
}

// Execute the request and cache the response for the specified duration
ActionExecutedContext executedContext = await next();

if (executedContext.Result is ObjectResult { StatusCode: >= 200 and < 300 } objectResult)
{
int statusCode = objectResult.StatusCode ?? StatusCodes.Status200OK;
IdempotentResponse response = new(statusCode, objectResult.Value);

await cache.SetStringAsync(
cacheKey,
JsonSerializer.Serialize(response),
new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = _cacheDuration }
);
}
}
}

internal sealed class IdempotentResponse
{
[JsonConstructor]
public IdempotentResponse(int statusCode, object? value)
{
StatusCode = statusCode;
Value = value;
}

public int StatusCode { get; }
public object? Value { get; }
}
More from @csharpgeeks
  1. Sep 22, 2026یه مدتی قراره از دنیای NET. فاصله بگیرم، چون وقتشه برم سربازی. راستش نمیدونم این مدت رو چج…
  2. Sep 20, 2026🔥 حالا مشکل اصلی: Alert Storm فرض کن Database از دسترس خارج شده. ۱۰۰ Pod داری. هر Pod می‌…
  3. Sep 20, 2026🚨 طراحی سیستم Monitoring و Alerting در یک سیستم بزرگ فرض کن ساعت ۳ صبح است. سیستم شما با…
  4. Sep 19, 2026#Engineering_Leadership تصمیم نگرفتن هم یک تصمیم است یه چیز عجیب توی تیم‌های مهندسی: گاهی…
  5. Sep 19, 2026☑ چک‌لیست آماده‌سازی تیم، فرایندها و زیرساخت برای توسعه با AI توجه: هیچ چک‌لیستی جهان‌شمول…
  6. Sep 19, 2026📌پایان یک انتظار طولانی: اعتبارسنجی ناهمگام (Async Validation) در NET 11.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →