لماذا لا يزال موقعك "يتحدث" مع المستخدم في الوقت الفعلي؟
\n\nتخيل: تفتح محطة تداول، وسعر الدولار يتجدد تلقائياً. أو تدخل لوحة الإدارة - وترى عدد المستخدمين المسجلين يتزايد أمام عينيك. أو دردشة حيث تصل الرسائل دون تحديثات مستمرة للصفحة.
\n\nفي السابق، كان عليك إما استخدام WebSocket (معقد، مكلف، ليس ضرورياً دائماً) أو استخدام long polling (حل مؤقت يستهلك بطارية الهاتف). لكن هناك طريق ثالث - الأحداث المرسلة من الخادم في C#.
\n\nاليوم سنشرح تقنية تسمح للخادم بـ"النقر" على العميل وإرسال البيانات. بدون كود زائد، بدون أطنان من JavaScript، بدون صداع مع خوادم الوكيل. فقط C#، فقط هاردكور.
\n\nما هي الأحداث المرسلة من الخادم (SSE) ولماذا ليست "بروتوكولاً للفقراء"
\n\nالأحداث المرسلة من الخادم (أو SSE) هي معيار HTML5 يسمح للخادم بإرسال بيانات متدفقة إلى العميل عبر اتصال HTTP عادي. العميل يشترك في الأحداث، والخادم يكتب ببساطة في Response.Body. هذا كل شيء.
\n\nالفرق الرئيسي عن WebSocket: SSE هي قناة أحادية الاتجاه (خادم ← عميل). لست بحاجة لإرسال البيانات مرة أخرى؟ ممتاز، SSE هو خيارك. مع ذلك:
\n\n- \n
- يعمل عبر HTTP/1.1 و HTTP/2 العاديين \n
- يعيد الاتصال تلقائياً عند الانقطاع (مدمج في
EventSourceفي المتصفح) \n - لا يتطلب مكتبات إضافية على العميل (باستثناء JavaScript القياسي) \n
- يمر عبر أي خوادم وكيل وموازنات تحميل (على عكس WebSocket) \n
عملياً، يُستخدم SSE C# من أجل:
\n- \n
- خلاصات الإشعارات (إشعارات دفع مباشرة إلى المتصفح) \n
- مراقبة الخوادم (لوحات معلومات بمقاييس حية) \n
- بث السجلات (مثل tail -f في المتصفح) \n
- تدفق توليدات الذكاء الاصطناعي (إخراج تدريجي من نماذج مشابهة لـ ChatGPT) \n
كيف يعمل SSE: بروتوكول في سطر واحد
\n\nكل شيء عبقري بسيط. الخادم يرسل للعميل تدفقاً من النص بتنسيق خاص:
\n\ndata: مرحباً أيها العالم!\\n\\n\ndata: {"message": "JSON يعمل أيضاً"}\\n\\n\nevent: customEvent\\n\ndata: حدث باسم\\n\\n\n\nكل رسالة تبدأ بـ data:، وتنتهي بسطرين جديدين. يمكن تحديد event: لنوع حدث مخصص، id: للمعرف، و retry: لمهلة إعادة الاتصال.
العميل في JavaScript يشترك كالتالي:
\n\nconst source = new EventSource("/api/stream");\nsource.onmessage = (event) => {\n console.log("تم الاستلام:", event.data);\n};\nsource.addEventListener("customEvent", (event) => {\n console.log("حدث مخصص:", event.data);\n});\n\nوهذا يعمل في جميع المتصفحات الحديثة. لا حاجة لحزم npm، ولا حاجة لـ WebSocket polyfills.
\n\nالأحداث المرسلة من الخادم في C#: التنفيذ على ASP.NET Core
\n\nدعنا أخيراً نكتب الكود. أبسط طريقة لتنظيم SSE في C# هي نقطة نهاية (endpoint) في ASP.NET Core لا تنهي الاستجابة، بل تكتب فيها على أجزاء.
\n\nنقطة نهاية SSE أساسية
\n\nusing Microsoft.AspNetCore.Mvc;\n\n[ApiController]\n[Route("api")]\npublic class StreamController : ControllerBase\n{\n [HttpGet("stream")]\n public async Task Get(CancellationToken cancellationToken)\n {\n Response.Headers.Append("Content-Type", "text/event-stream");\n Response.Headers.Append("Cache-Control", "no-cache");\n Response.Headers.Append("Connection", "keep-alive");\n\n for (int i = 0; i < 10; i++)\n {\n if (cancellationToken.IsCancellationRequested)\n break;\n\n // تنسيق SSE: data: ... \\n\\n\n await Response.WriteAsync($"data: رسالة #{i}\\n\\n",