TGViewer
C# Geeks (.NET) C# Geeks (.NET) @csharpgeeks · 550 subscribers
Post #557 252
مدیریت رویدادهای از‌دست‌رفته (Handling Missed Events) 🔄📡

ءEndpoint ساده‌ای که همین الان ساختیم عالی است، اما یک ضعف مهم دارد:
تاب‌آوری (Resilience) ندارد.

یکی از بزرگ‌ترین چالش‌ها در استریم‌های Real-time، قطع شدن اتصال است.
تا زمانی که مرورگر به‌صورت خودکار دوباره وصل شود، ممکن است چندین رویداد ارسال شده و از دست رفته باشند 😕

برای حل این مشکل، SSE یک مکانیزم داخلی دارد:
هدر Last-Event-ID.
وقتی مرورگر reconnect می‌شود، این ID را دوباره برای سرور ارسال می‌کند.

در NET 10. می‌توانیم از نوع <SseItem<T استفاده کنیم تا داده را به‌همراه متادیتاهایی مثل ID و retry interval بسته‌بندی کنیم.

با ترکیب یک OrderEventBuffer ساده‌ی درون‌حافظه‌ای و مقدار Last-Event-ID که مرورگر ارسال می‌کند، می‌توانیم رویدادهای از‌دست‌رفته را هنگام reconnect دوباره ارسال کنیم 🔁
app.MapGet("orders/realtime/with-replays", (
ChannelReader<OrderPlacement> channelReader,
OrderEventBuffer eventBuffer,
[FromHeader(Name = "Last-Event-ID")] string? lastEventId,
CancellationToken cancellationToken) =>
{
async IAsyncEnumerable<SseItem<OrderPlacement>> StreamEvents()
{
// 1. بازپخش رویدادهای از‌دست‌رفته از buffer
if (!string.IsNullOrWhiteSpace(lastEventId))
{
var missedEvents = eventBuffer.GetEventsAfter(lastEventId);
foreach (var missedEvent in missedEvents)
{
yield return missedEvent;
}
}

// 2. استریم رویدادهای جدید به‌محض ورود به Channel
await foreach (var order in channelReader.ReadAllAsync(cancellationToken))
{
var sseItem = eventBuffer.Add(order); // Buffer یک ID یکتا اختصاص می‌دهد
yield return sseItem;
}
}

return TypedResults.ServerSentEvents(StreamEvents(), "orders");
});


فیلتر کردن Server-Sent Events بر اساس کاربر 👤🔐

ءSSE روی HTTP استاندارد ساخته شده است.
چون یک درخواست GET معمولی است، زیرساخت فعلی شما بدون تغییر کار می‌کند:

ءSecurity 🔐: می‌توانید JWT را به‌صورت عادی در هدر Authorization ارسال کنید

ءUser Context 👤: می‌توانید به HttpContext.User دسترسی داشته باشید و استریم را بر اساس UserId فیلتر کنید
→ فقط داده‌هایی که متعلق به همان کاربر هستند ارسال می‌شوند

مثال یک Endpoint SSE که فقط سفارش‌های کاربر لاگین‌شده را استریم می‌کند:
app.MapGet("orders/realtime", (
ChannelReader<OrderPlacement> channelReader,
IUserContext userContext, // کانتکست تزریق‌شده شامل اطلاعات کاربر
CancellationToken cancellationToken) =>
{
// UserId از JWT توسط IUserContext استخراج می‌شود
var currentUserId = userContext.UserId;

async IAsyncEnumerable<OrderPlacement> GetUserOrders()
{
await foreach (var order in channelReader.ReadAllAsync(cancellationToken))
{
// فقط داده‌های متعلق به کاربر احراز هویت‌شده ارسال می‌شود
if (order.CustomerId == currentUserId)
{
yield return order;
}
}
}

return Results.ServerSentEvents(GetUserOrders(), "orders");
})
.RequireAuthorization(); // Authorization استاندارد ASP.NET Core


⚠️ نکته مهم:

وقتی یک پیام داخل Channel نوشته می‌شود، به تمام کلاینت‌های متصل broadcast می‌شود.
این رفتار برای استریم‌های per-user ایده‌آل نیست.
در محیط production، احتمالاً به راهکار قوی‌تری نیاز دارید.

مصرف Server-Sent Events در JavaScript 🌐🧠

در سمت کلاینت، نیازی به نصب حتی یک پکیج npm هم ندارید 🙌 API بومی مرورگر یعنی EventSource تمام کارهای سنگین را انجام می‌دهد،
از جمله reconnect خودکار و ارسال Last-Event-ID.
const eventSource = new EventSource('/orders/realtime/with-replays');

// گوش دادن به event type مشخص‌شده در C#
eventSource.addEventListener('orders', (event) => {
const payload = JSON.parse(event.data);
console.log(New Order ${event.lastEventId}:, payload.data);
});

// وقتی اتصال برقرار می‌شود
eventSource.onopen = () => {
console.log('Connection opened');
};

// پیام‌های عمومی (در صورت وجود)
eventSource.onmessage = (event) => {
console.log('Received message:', event);
};

// مدیریت خطا و reconnect
eventSource.onerror = () => {
if (eventSource.readyState === EventSource.CONNECTING) {
console.log('Reconnecting...');
}
};
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 →