
Viewer ไม่มีสถานะ — วิธีสร้าง Minimal .NET 8 Open Endpoint
Viewer ไม่มีสถานะ — ตามการออกแบบ
Viewer ไม่ เก็บข้อมูลเอกสารต่อคำขอใด ๆ. มันเป็นคลาสที่ปิดไม่ให้สืบทอด, มันไม่เคยทำการ implement IDisposable, และเอกสารทุกไฟล์ที่คุณเปิดจะอยู่ในเซสชันแยกที่แคชของเฟรมเวิร์กจัดการ. ด้วยเหตุนี้คุณสามารถ inject อินสแตนซ์ Viewer เพียงตัวเดียวได้ทุกที่ในแอป ASP.NET Core ของคุณและเรียกใช้งานได้อย่างปลอดภัยจากหลายคำขอพร้อมกัน.
ผลของบริการที่ไม่มีสถานะ
- ไม่มีทรัพยากรที่ซ่อนอยู่ – บริการเองไม่เคยจัดสรรบัฟเฟอร์ขนาดใหญ่ที่ต้องทำความสะอาดอย่างชัดเจน.
- ปลอดภัยต่อเธรดโดยค่าเริ่มต้น – เนื่องจากไม่มีสถานะเฉพาะคำขอถูกเก็บ, อินสแตนซ์
Viewerเดียวกันสามารถใช้ได้หลายเธรดโดยไม่ต้องล็อก. - การปรับใช้ที่ขยายได้ – การสเกลแนวนอนทำงานได้ทันที; คุณไม่ต้องการ sticky sessions หรือ server affinity, มีเพียง session token ที่ลูกค้าถืออยู่.
ข้อมูลเฉพาะเอกสารทั้งหมด (หน้า, คำอธิบาย, ดัชนีการค้นหา) ถูกเก็บไว้ใน session ที่สร้างโดย OpenDocumentAsync. เซสชันถูกจัดเก็บใน IMemoryCache (หรือ IDistributedCache ใด ๆ ที่คุณกำหนดค่า) และหมดอายุโดยอัตโนมัติหลังจากช่วงเวลาที่ไม่มีการใช้งาน (ค่าเริ่มต้น 60 นาที). เมื่อเสร็จสิ้นคุณสามารถเรียก CloseDocument เพื่อปล่อยรายการแคชก่อนเวลา.
การลงทะเบียน Viewer ที่ไม่มีสถานะ
เนื่องจาก Viewer ไม่มีสถานะที่เปลี่ยนแปลงได้, ลงทะเบียนมันครั้งเดียวในช่วงเริ่มต้น:
builder.Services.AddDoconut(); // ลงทะเบียน Viewer และ middleware ที่จำเป็น
builder.Services.AddSession(); // จำเป็นสำหรับความปลอดภัยของ token
builder.Services.AddDistributedMemoryCache(); // แคชง่ายสำหรับการสาธิต
การเรียก AddDoconut ยังเชื่อมต่อ middleware ที่ให้บริการทรัพยากร static ของ viewer. หลังจากบริการพร้อมคุณสามารถร้องขอ Viewer ในลายเซ็นของ endpoint ใดก็ได้.
Endpoint เปิดเอกสารแบบ Minimal (ตัวอย่าง net‑8)
โค้ดต่อไปนี้เป็นส่วนที่ตรงจากเอกสารอย่างเป็นทางการและทำงานได้ทันทีในโครงการ .NET 8 minimal‑API:
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ที่ไม่มีสถานะสร้างเซสชันใหม่, เก็บไว้ในแคช, และคืนค่า token ที่ไม่เปิดเผย. - คืน token เป็นข้อความธรรมดา – ลูกค้าได้รับเฉพาะ token; เซิร์ฟเวอร์ไม่เคยส่งไบต์ของเอกสารในการตอบกลับนี้.
เนื่องจาก Viewer ไม่เก็บข้อมูลเอกสาร, endpoint ไม่ต้องการบล็อก using, การเรียก Dispose, หรือ factory ต่อคำขอ. token เป็นข้อมูลรับรองเดียวที่ลูกค้าจะส่งกลับไปยัง widget ของ viewer (objViewer.View(token) บน front‑end).
การใช้ token ฝั่งไคลเอนต์
หลังจากที่ token ถูกคืน, widget บน front‑end จะเรียก objViewer.View(token). widget จากนั้นจะแนบ token เดียวกันกับทุกคำขอถัดไปสำหรับภาพหน้า, การค้นหา, หรือการกระทำ annotation. เซิร์ฟเวอร์ตรวจสอบ token กับเซสชันที่เปิดเอกสารครั้งแรก. หาก token ถูกนำเสนอจากเซสชันเบราว์เซอร์อื่น, viewer จะคืนข้อผิดพลาดการอนุญาต, ซึ่งเป็นพฤติกรรมความปลอดภัยตามที่ตั้งใจ.
การปิดเซสชันก่อนเวลา (เลือกได้)
หาก workflow ของคุณรู้ว่าเอกสารจะไม่ถูกเข้าถึงอีก, คุณสามารถปล่อยรายการแคชโดยเรียก CloseDocument บน Viewer. การทำเช่นนี้จะลบเซสชันออกจากแคชและป้องกันตัวจับเวลาการหมดอายุแบบ sliding‑expiration จากการทำให้มันยังคงอยู่.
สรุปกระบวนการที่ไม่มีสถานะ
| ขั้นตอน | เกิดอะไรขึ้น | ที่เก็บสถานะ |
|---|---|---|
| Inject Viewer | อินสแตนซ์ Viewer เดียวถูกสร้างในช่วงเริ่มต้น. | ใน DI container (singleton). |
| OpenDocumentAsync | ตรวจสอบไลเซนส์ → สร้างเซสชัน → คืน token. | เซสชันถูกจัดเก็บใน IMemoryCache (หรือ distributed cache). |
| Client renders | Widget ส่ง token พร้อมทุกคำขอ. | Token เป็นข้อมูลเอกสารเดียวที่ลูกค้าถือ. |
| Session expiration / CloseDocument | รายการแคชถูกลบหลังจากหมดเวลา หรือปิดโดยเจตนา. | ไม่มีทรัพยากรค้างคาในบริการ Viewer. |
ตอนนี้คุณสามารถสเกลเว็บฟาร์มของคุณได้อย่างปลอดภัย, เปลี่ยนโหนด, หรือรีสตาร์ทแอปพลิเคชันโดยไม่สูญเสียสถานะที่ผู้ใช้มองเห็น—เพียง token จะหมดอายุและทำให้ลูกค้าต้องเปิดเอกสารใหม่อีกครั้ง.
การปรับใช้ Viewer ที่ไม่มีสถานะในแอปของคุณ
- เพิ่ม
AddDoconut,AddSession, และผู้ให้บริการแคชไปยังProgram.cs. - วางส่วนโค้ด open‑endpoint ลงในการกำหนดค่า minimal‑API ของคุณ.
- ส่ง token ที่คืนให้กับ
objViewer.View(token)บน front‑end.
ตอนนี้คุณมี API เปิดเอกสารที่ไม่มีสถานะ, พร้อมใช้งานในระดับ production, ที่ใช้ประโยชน์จากการออกแบบ Viewer ของ Doconut.