איך הצופה עובד
מחזור חיי בקשת המסמך
Doconut מציג מסמכים כתמונות ממודפדות המוגשות דרך Middleware של ASP.NET Core. הבנת מחזור החיים — פתיחה, אסימון, בקשות דף, סגירה — מסבירה כמעט כל התנהגות שתצפו, כולל הודעות השגיאה.
שלושת החלקים המתנועים
Viewer— השירות הציבורי שאתה מוזרק. הוא פותח מסמכים ומחזיר אסימוני סשן.- הסשן של המסמך — אובייקט בצד השרת המחזיק את המסמך הטעון, ממופה לפי אסימון ב-
IMemoryCache. - ה‑Middleware של Doconut — מתווסף על ידי
UseDoconut(); משיב לכל בקשה שהווידג'ט של הדפדפן מבצע (pages,thumbnails,search,annotations, …), תמיד מאומת באמצעות האסימון.
Viewer הוא חסר מצב — לפי תכנון
Viewer סגור (sealed), אינו מחזיק במצב מסמך לכל בקשה, ובכוונה לא מיישם IDisposable. סשנים חיים באופן עצמאי במנהל הסשנים ומנוקים על ידי תפוגת המטמון או CloseDocument(token) מפורש.
הזרק אותו בכל מקום שבו אתה צריך אותו:
app.MapPost("/api/open", async (string fileName, Viewer viewer) =>
{
var token = await viewer.OpenDocumentAsync($"files/{fileName}");
return Results.Content(token, "text/plain");
});מה קורה בתוך OpenDocumentAsync
- שער הרישיון. רישיון שנדחה או שפג תוקפו (שחור, מזויף, או בנייה מחוץ לחלון העדכון של הרישיון) זורק
LicenseExceptionמיידית, עם סיבת הדחייה כהודעה — הפתיחה לעולם לא מתדרדרת בשקט עבור רישיון לא תקף (בניגוד לחסר רישיון). רישיון זמני שפג תוקפו או רישיון מנוי הוא היוצא מן הכלל: הוא לא זורק — הוא מתדרדר למים קבועים. - יצירת סשן. מפעל הצופה בוחר את הצופה המתאים לפורמט של סיומת הקובץ וטוען את המסמך (ראו Rendering Pipeline). הסשן נשמר ב-
IMemoryCacheתחת אסימון GUID חדש עם תפוגה מחליק —DocOptions.TimeOutדקות, ברירת מחדל 60. כל בקשת דף מאפסת את השעון. - רישום אבטחה. עם
UnsafeMode = false(ברירת המחדל), האסימון קשור לסשן ASP.NET של המבקש: סמןsecure-{token}נכתב לתוך הסשן, כך שרק סשן הדפדפן שפתח את המסמך יכול לבקש את הדפים שלו. - האסימון מוחזר. הוא האסימון היחיד לכל מה שיבוא לאחר מכן.
שלושת העומסים השונים נבדלים רק בקלט: נתיב קובץ, נתיב קובץ בתוספת תצורת פורמט (PdfConfig, WordConfig, …), או Stream בתוספת FileInfo שהסיומת שלו מגדירה את זיהוי הפורמט.
איך הווידג'ט מקבל דפים
הווידג'ט של הלקוח קורא ל‑Middleware של Doconut עם האסימון במחרוזת השאילתה. מה שה‑Middleware עושה תלוי בבקשה:
| שאילתה | מטרה |
|---|---|
?token=…&page=N | תמונת דף מרונדרת (PNG) |
?token=…&page=N&thumb=1 | תמונה ממוזערת |
?token=…&zoom=… | רינדור דף עם זום |
?token=…&search=term | חיפוש טקסט מלא (מוגן ברישיון) |
?token=…&bookmarks | מתאר המסמך / סימניות |
?token=…© / &showlinks / &fileFormat | העתקת טקסט, קישורים והמידע על הפורמט |
?token=…&meta | מטא-נתונים טכניים של DICOM; מחזיר 501 עבור סשן DICOM ב‑.NET 6 |
?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.
סגירת מסמך
viewer.CloseDocument(token);CloseDocument מסיר את הסשן מהמטמון (שמשחרר את מנוע המסמך הבסיסי ומשחרר את הזיכרון שלו מייד), מוחק את הסמן secure-{token}, ומבטל את ההרשאה לגישה. קריאה אליו היא אופציונלית — תפוגה מחליק עושה את הניקוי באופן אוטומטי — אך עבור מסמכים גדולים זו הדרך המנומסת לשחרר זיכרון ברגע שהמשתמש סיים.
מסקנות
- מסמך פתוח אחד = סשן אחד = אסימון אחד. אסימונים הם לכל סשן דפדפן, לא כתובות URL גלובליות.
- האסימון פג בתפוגה מחליקה; צופה שנשאר במצב מנוחה מעבר ל‑
DocOptions.TimeOutצריך פתיחה מחדש. - ניתן להזריק ולשתף את
Viewerבחופשיות; הסשנים נושאים את כל המצב.
האם דף זה היה מועיל?