العارض لا حالة — كيفية بناء نقطة نهاية مفتوحة .NET 8 بسيطة
← Back to Blog••4 min read

العارض لا حالة — كيفية بناء نقطة نهاية مفتوحة .NET 8 بسيطة

العارض لا حالة — حسب التصميم

Viewer لا يحفظ أي بيانات مستند لكل طلب. إنها فئة مغلقة، ولا تنفّذ أبداً IDisposable، وكل مستند تفتحه يعيش في جلسة منفصلة تديرها ذاكرة التخزين المؤقت للإطار. بسبب ذلك يمكنك حقن نسخة واحدة من Viewer في أي مكان داخل تطبيق ASP.NET Core الخاص بك واستدعاؤها بأمان من طلبات متزامنة متعددة.


عواقب خدمة بدون حالة

  • لا موارد مخفية – الخدمة نفسها لا تخصّص أبداً مخازن كبيرة تحتاج إلى تنظيف صريح.
  • آمن للخطوط الافتراضي – لأنه لا يتم تخزين حالة خاصة بالطلب، يمكن استخدام نفس نسخة Viewer من قبل عدة خيوط دون قفل.
  • نشر قابل للتوسع – التوسيع الأفقي يعمل مباشرةً؛ لا تحتاج إلى جلسات ثابتة أو ارتباط الخادم، فقط رمز الجلسة الذي يحتفظ به العميل.

جميع المعلومات الخاصة بالمستند (الصفحات، التعليقات التوضيحية، فهرس البحث) تُحفظ في جلسة تم إنشاؤها بواسطة OpenDocumentAsync. تُخزن الجلسة في IMemoryCache (أو أي IDistributedCache تقوم بتكوينه) وتنتهي تلقائيًا بعد فترة من عدم النشاط (الافتراضي 60 دقيقة). عندما تنتهي يمكنك استدعاء CloseDocument لتحرير مدخل الذاكرة المؤقتة مبكرًا.


تسجيل العارض بدون حالة

نظرًا لأن Viewer لا يمتلك حالة قابلة للتغيير، سجّله مرة واحدة أثناء بدء التشغيل:

builder.Services.AddDoconut();               // يسجل Viewer والـ middleware المطلوب
builder.Services.AddSession();               // مطلوب لأمان token
builder.Services.AddDistributedMemoryCache(); // ذاكرة تخزين مؤقت بسيطة للـ demo

استدعاء AddDoconut يربط أيضًا middleware الذي يقدم الموارد الثابتة للعارض. بعد إعداد الخدمات يمكنك طلب Viewer في أي توقيع نقطة نهاية.


نقطة نهاية فتح المستند البسيطة (مثال net‑8)

الكود التالي هو المقتطف الدقيق من الوثائق الرسمية ويعمل مباشرةً في مشروع .NET 8 minimal‑API:

app.MapPost("/api/open", async (string fileName, Viewer viewer) =>
{
    var token = await viewer.OpenDocumentAsync($"files/{fileName}");
    return Results.Content(token, "text/plain");
});

ما يفعله الكود

  1. يقبل اسم ملف – العميل يخبر الخادم أي ملف تحت wwwroot/files يجب فتحه.
  2. ينادي OpenDocumentAsync – العارض بدون حالة Viewer ينشئ جلسة جديدة، يخزنها في الذاكرة المؤقتة، ويعيد رمزًا غير شفاف.
  3. يرجع الرمز كنص عادي – يتلقى العميل الرمز فقط؛ الخادم لا يرسل أبدًا بايتات المستند في هذا الرد.

نظرًا لأن Viewer لا يحمل بيانات المستند، لا تحتاج نقطة النهاية إلى كتل using، أو استدعاءات Dispose، أو مصانع لكل طلب. الرمز هو الاعتماد الوحيد الذي سيُرسله العميل مرةً أخرى إلى واجهة العارض (objViewer.View(token) على الواجهة الأمامية).


استخدام الرمز على جانب العميل

بعد إرجاع الرمز، تستدعي واجهة الواجهة الأمامية objViewer.View(token). ثم تُضمّن الواجهة نفس الرمز مع كل طلب لاحق لصور الصفحات أو البحث أو إجراءات التعليقات. يتحقق الخادم من صحة الرمز مقابل الجلسة التي فتحت المستند أصلاً. إذا تم تقديم الرمز من جلسة متصفح مختلفة، يعيد العارض خطأ تفويض، وهو السلوك الأمني المقصود.


إغلاق جلسة مبكرًا (اختياري)

إذا كان سير العمل الخاص بك يعلم أن المستند لن يُستَخدم مرة أخرى، يمكنك تحرير مدخل الذاكرة المؤقتة عن طريق استدعاء CloseDocument على Viewer. هذا يزيل الجلسة من الذاكرة المؤقتة ويمنع مؤقت الانتهاء المتدرج من إبقائها نشطة.


ملخص تدفق الخدمة بدون حالة

الخطوةما يحدثأين توجد الحالة
حقن العارضيتم إنشاء نسخة واحدة من Viewer عند بدء التشغيل.في حاوية DI (واحد).
OpenDocumentAsyncتم التحقق من الترخيص → تم إنشاء الجلسة → تم إرجاع الرمز.الجلسة مخزنة في IMemoryCache (أو ذاكرة تخزين موزعة).
العميل يعرضالواجهة ترسل الرمز مع كل طلب.الرمز هو البيانات الوحيدة لكل مستند التي يحتفظ بها العميل.
انتهاء الجلسة / إغلاق المستندتم إزالة مدخل الذاكرة المؤقتة بعد انتهاء المهلة أو الإغلاق الصريح.لا توجد موارد متبقية في خدمة العارض.

نظرًا لأن الخدمة نفسها لا تخزن بيانات المستند، يمكنك توسيع مزرعة الويب بأمان، استبدال العقد، أو إعادة تشغيل التطبيق دون فقدان أي حالة مرئية للمستخدم — فقط الرمز يصبح غير صالح، مما يدفع العميل إلى إعادة فتح المستند.


نشر العارض بدون حالة في تطبيقك

  1. أضف AddDoconut، AddSession، ومزود ذاكرة تخزين مؤقت إلى Program.cs.
  2. الصق مقتطف نقطة النهاية المفتوحة في تكوين minimal‑API الخاص بك.
  3. مرّر الرمز المرجع إلى objViewer.View(token) على الواجهة الأمامية.

الآن لديك API لفتح المستندات بدون حالة تمامًا، جاهز للإنتاج، يستفيد من تصميم Viewer الخاص بـ Doconut.

#dotnet8#viewer#stateless#api#doconut#عارض#بدون حالة#واجهة برمجة التطبيقات