چگونه Viewer کار می‌کند

دورهٔ حیات درخواست سند

Doconut اسناد را به‌صورت تصاویر صفحه‌بندی‌شده که از طریق میدل‌ویر ASP.NET Core سرو می‌شوند، رندر می‌کند. درک دورهٔ حیات — باز کردن، توکن، درخواست‌های صفحه، بستن — تقریباً تمام رفتارهایی را که مشاهده می‌کنید، از جمله پیام‌های خطا، توضیح می‌دهد.

سه بخش متحرک

  • Viewer — سرویس عمومی که تزریق می‌کنید. اسناد را باز می‌کند و توکن‌های جلسه را برمی‌گرداند.
  • جلسهٔ سند — شیء سمت‑سرور که سند بارگذاری‌شده را نگه می‌دارد و با توکنی در IMemoryCache کلید می‌شود.
  • میان‌افزار Doconut — توسط UseDoconut() اضافه می‌شود؛ به هر درخواست که ویجت مرورگر می‌فرستد (pages، thumbnails، search، annotations، …) پاسخ می‌دهد و همیشه با توکن احراز هویت می‌شود.

Viewer بدون حالت است — به‌صورت پیش‌فرض

Viewer sealed است، هیچ وضعیت سندی برای هر درخواست نگه نمی‌دارد و عمداً پیاده‌سازی IDisposable نمی‌کند. جلسات به‌صورت مستقل در مدیر جلسه زندگی می‌کنند و توسط انقضای کش یا CloseDocument(token) صریح پاک می‌شوند.

در هر جایی که نیاز دارید آن را تزریق کنید:

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

چه اتفاقی داخل OpenDocumentAsync می‌افتد

  1. دروازهٔ مجوز. یک مجوز رد شده یا منقضی‌شدهٔ نسخه (سیاه‌لیست شده، دست‌کاری‌شده یا ساختی خارج از بازهٔ به‌روزرسانی مجوز) بلافاصله یک LicenseException پرتاب می‌کند، به همراه دلیل رد به‌عنوان پیام — باز کردن هرگز به‌صورت ساکت برای یک مجوز نامعتبر (در مقابل غیاب) کاهش کیفیت نمی‌یابد. مجوز موقت یا اشتراکی که تاریخ تقویمی‌اش منقضی شده است استثنا است: آن پرتاب نمی‌کند — به یک واترمارک کاهش می‌یابد.
  2. ایجاد جلسه. کارخانهٔ viewer فرمت مناسب viewer را بر اساس پسوند فایل انتخاب می‌کند و سند را بارگذاری می‌کند (به Rendering Pipeline مراجعه کنید). جلسه در IMemoryCache تحت یک توکن GUID تازه با انقضای لغزشیDocOptions.TimeOut دقیقه، پیش‌فرض ۶۰ — ذخیره می‌شود. هر درخواست صفحه ساعت را بازنشانی می‌کند.
  3. ثبت امنیتی. با UnsafeMode = false (پیش‌فرض)، توکن به جلسهٔ ASP.NET فراخواننده متصل می‌شود: یک نشانگر secure-{token} در جلسه نوشته می‌شود، به‌طوری‌که فقط جلسهٔ مرورگری که سند را باز کرده می‌تواند صفحات آن را درخواست کند.
  4. توکن برگردانده می‌شود. این توکن اعتبارنامهٔ واحد برای تمام عملیات بعدی است.

سه overload فقط در ورودی متفاوت هستند: یک مسیر فایل، مسیر فایل به‌همراه یک پیکربندی مخصوص فرمت (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 / &metaکپی متن، پیوندهای ابرمتنی، اطلاعات فرمت، فرادادهٔ فنی DICOM
?token=…&action=rotate/flip/closeعملیات صفحه و بستن صریح
?token=…&AnnSave=… / &AnnLoadذخیره/بارگذاری حاشیه‌نویسی‌ها

هر یک از این مسیرها ابتدا اعتبارسنجی می‌شوند:

  • بدون توکن → میدل‌ویر ۴۰۴ برمی‌گرداند (یا بنر نسخه وقتی 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.

بستن سند

csharp
viewer.CloseDocument(token);

CloseDocument جلسه را از کش حذف می‌کند (که موتور سند زیرین را آزاد می‌سازد و حافظهٔ آن را بلافاصله آزاد می‌کند)، نشانگر secure-{token} را پاک می‌کند و دسترسی را لغو می‌نماید. فراخوانی آن اختیاری است — انقضای لغزشی همان پاک‌سازی را به‌صورت خودکار انجام می‌دهد — اما برای اسناد بزرگ این روش مودبانه برای آزادسازی حافظه در همان لحظه‌ای است که کاربر کارش را تمام می‌کند.

نکات کلیدی

  • یک سند باز = یک جلسه = یک توکن. توکن‌ها به‌ازای هر جلسه مرورگر هستند، نه URLهای سراسری.
  • توکن در یک بازهٔ لغزشی منقضی می‌شود؛ اگر Viewer بیش از DocOptions.TimeOut بیکار بماند، نیاز به باز کردن مجدد دارد.
  • Viewer می‌تواند به‌آزادانه تزریق و به اشتراک گذاشته شود؛ جلسات تمام وضعیت را حمل می‌کنند.

آیا این صفحه مفید بود؟