
Viewer הוא ללא‑מצב — איך לבנות נקודת קצה פתוחה מינימלית ב‑.NET 8
Viewer הוא ללא‑מצב — לפי תכנון
Viewer לא שומר שום נתוני מסמך לכל בקשה. זהו מחלקה sealed, הוא אף פעם לא מממש IDisposable, וכל מסמך שאתה פותח נמצא במפגש נפרד שהמטמון של המסגרת מנהל. בגלל זאת אתה יכול להזריק מופע יחיד של Viewer בכל מקום באפליקציית ASP.NET Core שלך ולקרוא אליו בבטחה ממספר בקשות מקבילות.
השלכות של שירות ללא‑מצב
- אין משאבים מוסתרים – השירות עצמו אף פעם לא מקצה חוצצים גדולים שדורשים ניקוי מפורש.
- בטוח מבחינת תהליכים כברירת מחדל – מכיוון שאין מצב ספציפי לבקשה שמאוחסן, אותו מופע של
Viewerיכול לשמש מספר תהליכים ללא נעילה. - פריסות ניתנות להרחבה – קנה מידה אופקי עובד מייד; אינך צריך מפגשי דביקות או חיבוריות שרת, רק את אסימון המפגש שהלקוח מחזיק.
כל המידע הספציפי למסמך (דפים, אנוטציות, אינדקס חיפוש) נשמר במפגש שנוצר על ידי OpenDocumentAsync. המפגש מאוחסן בIMemoryCache (או בכל IDistributedCache שאתה מגדיר) ופג תוקף באופן אוטומטי לאחר תקופת חוסר פעילות (ברירת מחדל 60 דקות). כאשר סיימת, אתה יכול לקרוא לCloseDocument כדי לשחרר את רשומת המטמון מוקדם.
רישום ה-Viewer ללא‑מצב
מכיוון שViewer אין לו מצב ניתן לשינוי, רישמו פעם אחת בזמן האתחול:
builder.Services.AddDoconut(); // רושמת Viewer וה‑middleware הנדרש
builder.Services.AddSession(); // נדרש לאבטחת token
builder.Services.AddDistributedMemoryCache(); // מטמון פשוט ל‑demo
הקריאה לAddDoconut גם מחברת את ה‑middleware שמשרת את המשאבים הסטטיים של ה‑viewer. לאחר שהשירותים במקום, אתה יכול לבקש Viewer בכל חתימת נקודת קצה.
נקודת קצה פתיחת‑מסמך מינימלית (דוגמת net‑8)
הקוד הבא הוא הקטע המדויק מהתיעוד הרשמי ועובד מייד בפרויקט minimal‑API של .NET 8:
app.MapPost("/api/open", async (string fileName, Viewer viewer) =>
{
var token = await viewer.OpenDocumentAsync($"files/{fileName}");
return Results.Content(token, "text/plain");
});
מה הקוד עושה
- מקבל שם קובץ – הלקוח מודיע לשרת איזה קובץ תחת
wwwroot/filesלפתוח. - קורא ל
OpenDocumentAsync– ה‑Viewerללא‑מצב יוצר מפגש חדש, מאחסן אותו במטמון, ומחזיר אסימון בלתי נגיש. - מחזיר את האסימון כטקסט פשוט – הלקוח מקבל רק את האסימון; השרת אף פעם לא שולח את בתי המסמך בתגובה זו.
מכיוון שViewer אינו מחזיק נתוני מסמך, נקודת הקצה אינה זקוקה לחסימות using, קריאות Dispose, או מפעלים לכל בקשה. האסימון הוא האישור היחיד שהלקוח ישלח בחזרה לווידג'ט ה‑viewer (objViewer.View(token) בצד הקדמי).
שימוש באסימון בצד הלקוח
לאחר שהאסימון מוחזר, הווידג'ט בצד הקדמי קורא לobjViewer.View(token). הווידג'ט לאחר מכן כולל את אותו אסימון בכל בקשה נוספת לתמונות דפים, חיפוש, או פעולות אנוטציה. השרת מאמת את האסימון מול המפגש שפתח במקור את המסמך. אם האסימון מוצג ממפגש דפדפן שונה, ה‑viewer מחזיר שגיאת הרשאה, שהיא ההתנהגות האבטחתית המיועדת.
סגירת מפגש מוקדם (אופציונלי)
אם זרימת העבודה שלך יודעת שמסמך לעולם לא ייגש שוב, אתה יכול לשחרר את רשומת המטמון על‑ידי קריאה לCloseDocument על Viewer. פעולה זו מסירה את המפגש מהמטמון ומונעת ממנגנון ההפוגה המחליק לשמור אותו בחיים.
סיכום של זרימת ללא‑מצב
| שלב | מה קורה | היכן המצב נשמר |
|---|---|---|
| הזרקת Viewer | מופע יחיד של Viewer נוצר באתחול. | במכולת ה‑DI (singleton). |
| OpenDocumentAsync | בדיקת רישיון → יצירת מפגש → החזרת אסימון. | המפגש מאוחסן בIMemoryCache (או במטמון מבוזר). |
| הלקוח מציג | הווידג'ט שולח את האסימון עם כל בקשה. | האסימון הוא הנתון היחיד לכל מסמך שהלקוח מחזיק. |
| פג תוקף המפגש / CloseDocument | רשומת המטמון מוסרת לאחר זמן קצוב או סגירה מפורשת. | אין משאבים משאירים בשירות ה‑Viewer. |
מאחר שהשירות עצמו אף פעם לא מאחסן נתוני מסמך, אתה יכול להרחיב בבטחה את חוות האתרים שלך, להחליף צמתים, או לאתחל את היישום ללא איבוד מצב נראה למשתמש — רק האסימון הופך ללא תקף, מה שמגרה את הלקוח לפתוח מחדש את המסמך.
פריסת ה‑Viewer ללא‑מצב באפליקציה שלך
- הוסף את
AddDoconut,AddSession, וספק מטמון לProgram.cs. - הדבק את קטע הקוד של נקודת הקצה הפתוחה לתצורת ה‑minimal‑API שלך.
- העבר את האסימון שהוחזר ל
objViewer.View(token)בצד הקדמי.
כעת יש לך API פתיחת‑מסמך ללא‑מצב, מוכן לייצור, המנצלת את העיצוב של Doconut’s Viewer.