عنوان:

‫پشتیبانی توکار از رویدادهای ارسالی از سرور (Server-Sent Events) در ASP.NET Core و NET 10.


نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۲/۰۳ ۰۸:۲۲
آدرس: www.dntips.ir
مقدمه
در دنیای توسعه وب مدرن، ارائه به‌روزرسانی‌های لحظه‌ای (Real-Time) به کاربران از اهمیت ویژه‌ای برخوردار است. کاربران امروزی انتظار دارند که برنامه‌های وب به‌سرعت به تغییرات پاسخ دهند، مانند نمایش اعلان‌ها، به‌روزرسانی قیمت سهام یا نمایش پیام‌های جدید در چت. یکی از فناوری‌های قدرتمند برای دستیابی به این هدف، رویدادهای ارسالی از سرور (Server-Sent Events یا SSE) است که امکان ارسال داده‌های یک‌طرفه از سرور به کلاینت را فراهم می‌کند. این فناوری به دلیل سادگی، سبک بودن و پشتیبانی گسترده در مرورگرهای مدرن، گزینه‌ای ایده‌آل برای توسعه‌دهندگانی است که با چارچوب ASP.NET Core کار می‌کنند. این مقاله به بررسی چگونگی پیاده‌سازی رویدادهای ارسالی از سرور (SSE) در ASP.NET Core و نسخه .NET 10 می‌پردازد.

رویدادهای ارسالی از سرور (SSE) چیست؟
رویدادهای ارسالی از سرور (Server-Sent Events) یک استاندارد مبتنی بر پروتکل HTTP است که به سرور اجازه می‌دهد داده‌ها را به‌صورت یک‌طرفه و پیوسته به کلاینت (معمولاً مرورگر) ارسال کند. برخلاف فناوری‌هایی مانند وب‌سوکت (WebSocket) که ارتباط دوطرفه را فراهم می‌کنند، SSE برای سناریوهایی طراحی شده است که سرور نیاز دارد به‌روزرسانی‌های مداوم را به کلاینت ارسال کند، بدون اینکه کلاینت درخواست‌های مکرر ارسال کند. این ویژگی باعث کاهش سربار (Overhead) و مصرف منابع می‌شود.
SSE از فرمت متن مبتنی بر رویداد (Event Stream) استفاده می‌کند که داده‌ها را به‌صورت رشته‌های متنی با ساختار مشخص ارسال می‌کند. به‌عنوان مثال، یک پیام SSE می‌تواند به این شکل باشد:
event: message
data: {"symbol": "AAPL", "value": 150.25}
مزایای SSE شامل سادگی پیاده‌سازی، پشتیبانی گسترده در مرورگرها (مانند کروم، فایرفاکس و سافاری)، و استفاده از پروتکل HTTP استاندارد است که نیاز به زیرساخت‌های پیچیده را کاهش می‌دهد. بااین‌حال، محدودیت‌هایی مانند عدم پشتیبانی از ارتباط دوطرفه و وابستگی به اتصال پایدار HTTP نیز وجود دارد.

چرا از SSE در ASP.NET Core استفاده کنیم؟
چارچوب ASP.NET Core به دلیل انعطاف‌پذیری و عملکرد بالای خود، بستری مناسب برای پیاده‌سازی فناوری‌هایی مانند SSE است. در نسخه .NET 10، ابزارها و قابلیت‌های بهبودیافته‌ای برای مدیریت ارتباطات لحظه‌ای ارائه شده است که توسعه‌دهندگان را قادر می‌سازد برنامه‌هایی با کارایی بالا و مقیاس‌پذیر ایجاد کنند. استفاده از SSE در ASP.NET Core به‌ویژه برای سناریوهایی مانند نمایش به‌روزرسانی‌های قیمت سهام، اعلان‌های سیستمی، یا داشبوردهای مدیریتی مناسب است، زیرا نیازی به پیچیدگی‌های وب‌سوکت (WebSocket) یا کتابخانه‌های سنگین مانند SignalR ندارد.

پیاده‌سازی SSE در ASP.NET Core
برای پیاده‌سازی SSE در ASP.NET Core، باید یک نقطه پایانی (Endpoint) در سرور ایجاد کنیم که جریان داده‌ها را به کلاینت ارسال کند، و سپس در سمت کلاینت، از شیء EventSource در جاوااسکریپت برای دریافت این داده‌ها استفاده کنیم. در ادامه، مراحل پیاده‌سازی را به‌صورت گام‌به‌گام بررسی می‌کنیم.

1. تنظیم سرور در ASP.NET Core
ابتدا باید یک کنترلر (Controller) یا نقطه پایانی (Endpoint) در ASP.NET Core ایجاد کنیم که پاسخ‌های SSE را تولید کند. در اینجا، از یک کنترلر ساده برای شبیه‌سازی به‌روزرسانی قیمت سهام استفاده می‌کنیم:
using Microsoft.AspNetCore.Mvc;

namespace StockTracker.Controllers;

[Route("stock")]
public class StockController : Controller
{
    [HttpGet]
    public async Task Get()
    {
        Response.Headers.Append("Content-Type", "text/event-stream");
        Response.Headers.Append("Cache-Control", "no-cache");
        Response.Headers.Append("Connection", "keep-alive");

        var stocks = new[] { "AAPL", "GOOGL", "MSFT" };
        var random = new Random();

        while (!HttpContext.RequestAborted.IsCancellationRequested)
        {
            var symbol = stocks[random.Next(stocks.Length)];
            var value = 100 + random.NextDouble() * 100;
            await Response.WriteAsync($"event: {symbol}\n");
            await Response.WriteAsync($"data: {value:F2}\n\n");
            await Response.Body.FlushAsync();
            await Task.Delay(1000);
        }
    }
}
توضیح کد:
  • هدرها (Headers): تنظیم هدر Content-Type به text/event-stream برای مشخص کردن نوع پاسخ ضروری است. هدرهای Cache-Control و Connection نیز برای جلوگیری از ذخیره‌سازی پاسخ و حفظ اتصال استفاده می‌شوند.
  • حلقه به‌روزرسانی: در این کد، یک حلقه بی‌نهایت ایجاد شده است که هر ثانیه یک به‌روزرسانی تصادفی برای یکی از نمادهای سهام (AAPL، GOOGL، MSFT) ارسال می‌کند.
  • پشتیبانی از لغو درخواست: استفاده از HttpContext.RequestAborted تضمین می‌کند که در صورت قطع اتصال کلاینت، حلقه متوقف شود.
  • فرمت SSE: داده‌ها با فرمت استاندارد SSE (شامل event و data) ارسال می‌شوند و با دو خط جدید (\n\n) خاتمه می‌یابند.

2. ایجاد کلاینت با جاوااسکریپت
در سمت کلاینت، از شیء EventSource برای اتصال به نقطه پایانی سرور و دریافت به‌روزرسانی‌ها استفاده می‌کنیم. کد HTML زیر یک رابط کاربری ساده برای نمایش به‌روزرسانی‌های سهام ایجاد می‌کند:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Stock Tracker</title>
    <style>
        body { font-family: Arial, sans-serif; }
        #stocks { display: flex; flex-direction: column; gap: 10px; margin-top: 20px; }
        .stock { padding: 10px; border: 1px solid #ddd; border-radius: 5px; background-color: #f9f9f9; }
    </style>
</head>
<body>
    <h1>Stock Tracker</h1>
    <div id="stocks"></div>
    <script>
        const eventSource = new EventSource('http://localhost:5011/stock/');

        function updateStock(symbol, value) {
            let stockElement = document.getElementById(symbol);
            if (!stockElement) {
                stockElement = document.createElement('div');
                stockElement.id = symbol;
                stockElement.className = 'stock';
                document.getElementById('stocks').appendChild(stockElement);
            }
            stockElement.innerHTML = `<strong>${symbol}:</strong> ${value}`;
        }

        const symbols = ['AAPL', 'GOOGL', 'MSFT'];
        symbols.forEach(symbol => {
            eventSource.addEventListener(symbol, event => {
                updateStock(symbol, event.data);
            });
        });

        eventSource.onerror = function() {
            console.error('Connection to the server lost.');
        };
    </script>
</body>
</html>
توضیح کد:
  • اتصال به سرور: شیء EventSource به نقطه پایانی سرور (/stock) متصل می‌شود.
  • مدیریت رویدادها: برای هر نماد سهام، یک شنونده رویداد (Event Listener) تعریف شده است که داده‌های دریافتی را به‌روزرسانی می‌کند.
  • نمایش داده‌ها: تابع updateStock مسئول ایجاد یا به‌روزرسانی عناصر HTML برای نمایش قیمت سهام است.
  • مدیریت خطا: در صورت قطع اتصال، یک پیام خطا در کنسول نمایش داده می‌شود.

3. استفاده از کتابخانه‌های کمکی
برای سناریوهای پیچیده‌تر، می‌توان از کتابخانه‌هایی مانند Lib.AspNetCore.ServerSentEvents استفاده کرد. این کتابخانه قابلیت‌هایی مانند مدیریت کلاینت‌های متعدد و ارسال پیام‌های هدفمند را ساده‌تر می‌کند. برای نصب آن، از دستور زیر استفاده کنید:
dotnet add package Lib.AspNetCore.ServerSentEvents
پس از نصب، می‌توانید سرویس SSE را در فایل Program.cs ثبت کنید:
builder.Services.AddServerSentEvents();
سپس، از کلاس ServerSentEventsService برای مدیریت کلاینت‌ها و ارسال پیام‌ها استفاده کنید.

ارزش افزوده: مقایسه SSE با سایر فناوری‌ها
برای درک بهتر جایگاه SSE، مقایسه آن با فناوری‌های مشابه مفید است:
  • وب‌سوکت (WebSocket): برخلاف SSE، وب‌سوکت ارتباط دوطرفه را فراهم می‌کند، اما پیچیدگی بیشتری دارد و برای سناریوهای ساده ممکن است بیش از حد سنگین باشد.
  • SignalR: این کتابخانه مایکروسافت قابلیت‌های پیشرفته‌تری نسبت به SSE ارائه می‌دهد، اما برای پروژه‌های کوچک ممکن است اضافه‌بار (Overkill) باشد.
  • نظرسنجی طولانی (Long Polling): این روش قدیمی‌تر، سربار بیشتری نسبت به SSE دارد، زیرا کلاینت باید به‌صورت مکرر درخواست ارسال کند.

نکات عملی برای پیاده‌سازی موفق
  1. مدیریت اتصال: برای جلوگیری از قطع اتصال در محیط‌های خاص (مانند سرورهای پروکسی)، از تکنیک‌های نگه‌داری اتصال (Keep-Alive) استفاده کنید.
  2. مقیاس‌پذیری: در برنامه‌های بزرگ، از ابزارهایی مانند Redis یا Kafka برای مدیریت جریان داده‌ها استفاده کنید.
  3. امنیت: برای محافظت از داده‌ها، از HTTPS استفاده کنید و احراز هویت (Authentication) را در نقاط پایانی SSE پیاده‌سازی کنید.

نتیجه‌گیری
رویدادهای ارسالی از سرور (Server-Sent Events) یک راه‌حل ساده و کارآمد برای ارائه به‌روزرسانی‌های لحظه‌ای در برنامه‌های وب است. با استفاده از ASP.NET Core و .NET 10، توسعه‌دهندگان می‌توانند به‌راحتی نقاط پایانی SSE را ایجاد کرده و با کلاینت‌های مبتنی بر مرورگر ارتباط برقرار کنند. این فناوری به دلیل سبک بودن، سازگاری با HTTP و پشتیبانی گسترده، گزینه‌ای عالی برای سناریوهای مختلف مانند داشبوردهای مدیریتی یا اعلان‌های سیستمی است.


مشاهده مطلب اصلی

نظرات

  • سعید قاسمی در ۱۴۰۴/۰۲/۰۳ ۱۱:۲۲
    من با استفاده از این مقاله، SignalR و همچنین Websocket که در سایتم استفاده میکردم رو با SSE جایگزین کردم و از تغییر کاملا راضی هستم. چون از قبل هم ارتباط من یک طرفه بود. این روش برای سناریوی من خیلی سبک‌تر هست.