كيف يعمل Viewer

دورة حياة طلب المستند

Doconut يعرض المستندات كصور مقسمة إلى صفحات تُقدم عبر وسيط ASP.NET Core. فهم دورة الحياة — الفتح، الرمز، طلبات الصفحات، الإغلاق — يوضح تقريبًا كل سلوك ستلاحظه، بما في ذلك رسائل الأخطاء.

الأجزاء الثلاثة المتحركة

  • Viewer — الخدمة العامة التي تقوم بحقنها. تقوم بفتح المستندات وإرجاع رموز الجلسة.
  • جلسة المستند — كائن على جانب الخادم يحتفظ بالمستند المحمَّل، ومفتاحه رمز في IMemoryCache.
  • وسيط Doconut — يُضاف بواسطة UseDoconut()؛ يرد على كل طلب يرسله عنصر المتصفح (pages، thumbnails، search، annotations، …)، دائمًا مُصادَق بالرمز.

Viewer لا يحمل حالة — حسب التصميم

Viewer مغلق (sealed)، لا يحمل حالة مستند لكل طلب، ويتعمد عدم تنفيذ IDisposable. الجلسات تعيش بشكل مستقل في مدير الجلسات وتُنظَّف بانتهاء صلاحية الذاكرة المؤقتة أو عبر CloseDocument(token) صريح.

لم تعد تقوم بإنشائه. AddDoconut() تسجّله كخدمة متقلبة؛ قم بحقنه أينما احتجت إليه:

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

في تطبيق MVC، خذه كمعامل للمنشئ؛ في عرض Razor، استخدم @inject Doconut.Viewer Viewer. لم تعد الحاجة إلى مخازن مملوكة للتطبيق من مثيلات Viewer — ولم تعد صحيحة، لأنها لا تحتفظ بأي شيء يستحق التخزين.

ما يحدث داخل OpenDocumentAsync

  1. بوابة الترخيص. ترخيص مرفوض أو منتهي الصلاحية (محظور، مُتلاعب، أو بناء خارج نافذة تحديث الترخيص) يرمي استثناء LicenseException فورًا، مع سبب الرفض كرسالة — لا يتدهور الفتح بصمت عند ترخيص غير صالح (مقابل غائب). الترخيص المؤقت أو الاشتراك منتهي الصلاحية حسب التقويم هو الاستثناء: لا يرمي استثناء — يتدهور إلى علامة مائية.
  2. إنشاء الجلسة. تختار مصنع المشاهد (viewer) المشاهد المناسب لتنسيق امتداد الملف وتحمِّل المستند (انظر خط أنابيب العرض). تُخزن الجلسة في IMemoryCache تحت رمز GUID جديد مع انتهاء زمني انزلاقي — DocOptions.TimeOut دقيقة، الافتراضي 60. كل طلب صفحة يُعيد ضبط المؤقت.
  3. تسجيل الأمان. مع UnsafeMode = false (الإعداد الافتراضي)، يُربط الرمز بجلسة ASP.NET للمتصل: يُكتب علامة secure-{token} في الجلسة، بحيث لا يمكن إلا جلسة المتصفح التي فتحت المستند طلب صفحاته.
  4. يُعاد الرمز. هو الاعتماد الوحيد لكل ما يلي.

لا توجد خطوة إحماء منفصلة. المكتبة السابقة وفرت InitCache() لهذا الغرض؛ لم تعد موجودة، ولا شيء يحل محلها.

التحميلات الثلاثة تختلف فقط في المدخلات: مسار ملف، مسار ملف بالإضافة إلى تكوين لكل تنسيق (PdfConfig، WordConfig، …)، أو Stream مع FileInfo حيث يحدد الامتداد نوع التنسيق.

كيف يحصل الودجت على الصفحات

يتصل ودجت العميل بوسيط Doconut مع الرمز في سلسلة الاستعلام. ما يفعله الوسيط يعتمد على الطلب:

الاستعلامالغرض
?token=…&page=Nصورة صفحة مُصدَّرة (PNG)
?token=…&page=N&thumb=1صورة مصغرة
?token=…&zoom=…عرض صفحة مكبرة
?token=…&search=termبحث نص كامل (محكوم بالترخيص)
?token=…&bookmarksمخطط المستند/العلامات المرجعية
?token=…&copy / &showlinks / &fileFormatنسخ النص، الروابط التشعبية، ومعلومات التنسيق
?token=…&metaبيانات تعريف تقنية DICOM؛ يُعيد 501 لجلسة DICOM في هذه الحزمة
?token=…&action=rotate/flip/closeإجراءات الصفحة والإغلاق الصريح
?token=…&AnnSave=… / &AnnLoadحفظ/تحميل التعليقات التوضيحية

كل واحد من هذه المسارات يتحقق أولاً:

  • بدون رمز → يُعيد الوسيط 404 (أو لافتة نسخة عندما ShowDoconutInfo = true).
  • رمز غير معروف أو منتهي → صورة خطأ مع النص Document session not found. Please re-open document.
  • وسيط الجلسة مفقود (مع UnsafeMode = false) → HTTP 500 مع النص Session middleware not configured. Call UseSession() before UseDoconut().
  • الرمز مفتوح بواسطة جلسة متصفح مختلفة → صورة خطأ مع النص You Are Not Authorized To View This Page.

أين يتم تركيب الوسيط

UseDoconut() يرد على الطلبات التي تحمل رمزًا، أينما قمت بتركيبه. التطبيق المرجعي يحتفظ بشكل طلب DocImage.axd التاريخي على فرع MapWhen، لذا يواصل العميل الموجود استدعاء العنوان URL كما كان دائمًا. أيًا كان اختيارك، يجب أن يتطابق BasePath الخاص بالعميل معه — راجع إعدادات المشاهد.

خدمة الصفحات من تخزين مشترك بدلاً من عقدة الفتح هو ترتيب مختلف تمامًا؛ راجع النشر الموزع.

إغلاق المستند

csharp
viewer.CloseDocument(token);

CloseDocument يزيل الجلسة من الذاكرة المؤقتة (التي تُفرغ محرك المستند الأساسي وتحرّر ذاكرته فورًا)، يحذف علامة secure-{token}، ويلغي إذن الوصول. استدعاؤه اختياري — الانتهاء الزمني الانزلاقي يقوم بنفس التنظيف تلقائيًا — لكن للمستندات الكبيرة هو الطريقة المهذبة لتحرير الذاكرة فور انتهاء المستخدم.

يُستدعى على Viewer المُحقن. النمط السابق — إنشاء Viewer قصير العمر داخل كتلة using فقط لإغلاق رمز — لا يوجد له مكافئ ولا حاجة إليه.

الخلاصات

  • مستند مفتوح واحد = جلسة واحدة = رمز واحد. الرموز تخص كل جلسة متصفح، ليست عناوين URL عامة.
  • ينتهي صلاحية الرمز في نافذة انزلاقية؛ إذا ظل المشاهد غير نشط بعد DocOptions.TimeOut يحتاج إلى إعادة فتح.
  • يمكن حقن Viewer ومشاركته بحرية؛ الجلسات تحمل كل الحالة.

هل كانت هذه الصفحة مفيدة؟