איך הצופה עובד

מחזור חיי בקשת המסמך

Doconut מציג מסמכים כתמונות ממודפדות המוגשות דרך Middleware של ASP.NET Core. הבנת מחזור החיים — פתיחה, אסימון, בקשות דף, סגירה — מסבירה כמעט כל התנהגות שתראו, כולל הודעות השגיאה.

שלושת החלקים המניעים

  • Viewer — השירות הציבורי שאתה מוזרק. הוא פותח מסמכים ומחזיר אסימוני סשן.
  • הסשן של המסמך — אובייקט בצד השרת המחזיק את המסמך הטעון, ממופה באמצעות אסימון ב-IMemoryCache.
  • ה‑Middleware של 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. יצירת סשן. מפעל הצופה בוחר את הצופה המתאים לפורמט לפי סיומת הקובץ וטוען את המסמך (ראו Rendering Pipeline). הסשן מאוחסן ב-IMemoryCache תחת אסימון GUID חדש עם תפוגה מתחלפת — DocOptions.TimeOut דקות, ברירת מחדל 60. כל בקשת דף מאפסת את השעון.
  3. רישום אבטחה. עם UnsafeMode = false (ברירת המחדל), האסימון קשור לסשן ASP.NET של המבקש: סמן secure-{token} נכתב לתוך הסשן, כך שרק סשן הדפדפן שפתח את המסמך יכול לבקש את הדפים שלו.
  4. האסימון מוחזר. הוא האישור היחיד לכל מה שבא אחרי.

אין שלב חימום נפרד. הספרייה הקודמת חשפה InitCache() למטרה זו; הוא אינו קיים יותר, ואין מה שמחליף אותו.

שלושת העומסות (overloads) שונות רק בקלט: נתיב קובץ, נתיב קובץ בתוספת תצורת פורמט (PdfConfig, WordConfig, …), או Stream בתוספת FileInfo שהסיומת שלו מניעה את זיהוי הפורמט.

איך הווידג'ט מקבל דפים

הווידג'ט של הלקוח קורא ל‑Middleware של Doconut עם האסימון במחרוזת השאילתה. מה שה‑Middleware עושה תלוי בבקשה:

שאילתהמטרה
?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שמירת/טעינת אנוטציות

כל אחד מהנתיבים הללו מתבצע אימות תחילה:

  • אין אסימון → ה‑Middleware מחזיר 404 (או באנר גרסה כאשר ShowDoconutInfo = true).
  • אסימון לא ידוע או שפג → תמונת שגיאה עם Document session not found. Please re-open document.
  • חסר Middleware של סשן (עם UnsafeMode = false) → HTTP 500 עם Session middleware not configured. Call UseSession() before UseDoconut().
  • אסימון נפתח על‑ידי סשן דפדפן שונה → תמונת שגיאה עם You Are Not Authorized To View This Page.

היכן ה‑Middleware מותקן

UseDoconut() משיב לבקשות שנושאות אסימון, בכל מקום שבו אתם מתקינים אותו. היישום הרפרנסי שומר על צורת הבקשה ההיסטורית DocImage.axd בסניף MapWhen, כך שלקוח קיים ממשיך לקרוא ל‑URL שהוא תמיד קרא. כל מה שתבחרו, BasePath של הלקוח חייב להתאים לו — ראו ViewerConfig.

שרת דפים מאחסון משותף במקום מהצומת שפתח הוא סידור שונה לחלוטין; ראו Distributed Deployments.

סגירת מסמך

csharp
viewer.CloseDocument(token);

CloseDocument מסיר את הסשן מהמטמון (שמשחרר את מנוע המסמך הבסיסי ומשחרר את הזיכרון שלו מייד), מוחק את הסמן secure-{token} ומבטל את ההרשאה לגישה. קריאה אליו היא אופציונלית — תפוגה מתחלפת עושה את ניקוי הזיכרון באופן אוטומטי — אך עבור מסמכים גדולים זו הדרך המנומסת לשחרר זיכרון ברגע שהמשתמש סיים.

הקריאה מתבצעת על ה‑Viewer המוזרק. הדפוס הקודם — בניית Viewer קצר‑חיים ב‑using רק כדי לסגור אסימון — אין לו מקביל ואינו נדרש.

מסקנות

  • מסמך פתוח אחד = סשן אחד = אסימון אחד. אסימונים הם לכל סשן דפדפן, לא ל‑URL גלובלי.
  • האסימון פג בתפוגה מתחלפת; צופה שנשאר במצב מנוחה מעבר ל‑DocOptions.TimeOut צריך פתיחה מחדש.
  • ניתן להזריק ולשתף את Viewer בחופשיות; הסשנים נושאים את כל המצב.

האם דף זה היה מועיל?