Viewer không trạng thái — Cách xây dựng một Endpoint mở Minimal .NET 8
← Back to Blog••5 min read

Viewer không trạng thái — Cách xây dựng một Endpoint mở Minimal .NET 8

Viewer không trạng thái — theo thiết kế

Viewer không giữ bất kỳ dữ liệu tài liệu nào theo yêu cầu. Đây là một lớp sealed, nó không bao giờ triển khai IDisposable, và mỗi tài liệu bạn mở tồn tại trong một phiên riêng mà bộ nhớ đệm của framework quản lý. Vì vậy bạn có thể tiêm một thể hiện Viewer duy nhất ở bất kỳ đâu trong ứng dụng ASP.NET Core của mình và an toàn gọi nó từ nhiều yêu cầu đồng thời.


Hậu quả của dịch vụ không trạng thái

  • Không có tài nguyên ẩn – dịch vụ tự nó không bao giờ cấp phát các bộ đệm lớn cần dọn dẹp rõ ràng.
  • An toàn đa luồng theo mặc định – vì không có trạng thái riêng cho mỗi yêu cầu, cùng một thể hiện Viewer có thể được sử dụng bởi nhiều luồng mà không cần khóa.
  • Triển khai có khả năng mở rộng – việc mở rộng ngang hoạt động ngay lập tức; bạn không cần phiên dính hay gắn máy chủ, chỉ cần token phiên mà khách hàng giữ.

Tất cả thông tin riêng của tài liệu (trang, chú thích, chỉ mục tìm kiếm) được giữ trong một phiên được tạo bởi OpenDocumentAsync. Phiên được lưu trong IMemoryCache (hoặc bất kỳ IDistributedCache nào bạn cấu hình) và tự động hết hạn sau một khoảng thời gian không hoạt động (mặc định 60 phút). Khi hoàn tất, bạn có thể gọi CloseDocument để giải phóng mục bộ nhớ đệm sớm.


Đăng ký Viewer không trạng thái

Vì Viewer không có trạng thái có thể thay đổi, hãy đăng ký nó một lần trong quá trình khởi động:

builder.Services.AddDoconut();               // đăng ký Viewer và middleware cần thiết
builder.Services.AddSession();               // cần thiết cho bảo mật token
builder.Services.AddDistributedMemoryCache(); // bộ nhớ cache đơn giản cho bản demo

Lệnh gọi AddDoconut cũng kết nối middleware phục vụ các tài nguyên tĩnh của viewer. Sau khi các dịch vụ đã sẵn sàng, bạn có thể yêu cầu Viewer trong bất kỳ chữ ký endpoint nào.


Endpoint mở tài liệu tối thiểu (ví dụ net‑8)

Mã sau là đoạn trích chính xác từ tài liệu chính thức và hoạt động ngay lập tức trong một dự án .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");
});

Những gì mã thực hiện

  1. Chấp nhận tên tệp – khách hàng thông báo cho máy chủ tệp nào dưới wwwroot/files cần mở.
  2. Gọi OpenDocumentAsync – Viewer không trạng thái tạo một phiên mới, lưu nó vào bộ nhớ đệm, và trả về một token không trong suốt.
  3. Trả về token dưới dạng văn bản thuần – khách hàng chỉ nhận token; máy chủ không bao giờ gửi dữ liệu byte của tài liệu trong phản hồi này.

Vì Viewer không giữ dữ liệu tài liệu nào, endpoint không cần các khối using, các lời gọi Dispose, hoặc các nhà máy theo yêu cầu. Token là thông tin xác thực duy nhất mà khách hàng sẽ gửi lại cho widget viewer (objViewer.View(token) ở phía front‑end).


Sử dụng token ở phía khách hàng

Sau khi token được trả về, widget front‑end gọi objViewer.View(token). Widget sau đó bao gồm cùng một token trong mọi yêu cầu tiếp theo cho hình ảnh trang, tìm kiếm, hoặc hành động chú thích. Máy chủ xác thực token dựa trên phiên đã mở tài liệu ban đầu. Nếu token được trình bày từ một phiên trình duyệt khác, viewer sẽ trả về lỗi ủy quyền, đây là hành vi bảo mật dự định.


Đóng phiên sớm (tùy chọn)

Nếu quy trình của bạn biết rằng một tài liệu sẽ không bao giờ được truy cập lại, bạn có thể giải phóng mục bộ nhớ đệm bằng cách gọi CloseDocument trên Viewer. Điều này sẽ xóa phiên khỏi bộ nhớ đệm và ngăn timer hết hạn trượt giữ nó còn hoạt động.


Tóm tắt luồng không trạng thái

BướcĐiều gì xảy raNơi trạng thái tồn tại
Tiêm ViewerMột thể hiện Viewer duy nhất được tạo tại khởi động.Trong container DI (singleton).
OpenDocumentAsyncKiểm tra giấy phép → tạo phiên → trả về token.Phiên được lưu trong IMemoryCache (hoặc bộ nhớ đệm phân tán).
Client hiển thịWidget gửi token cùng mỗi yêu cầu.Token là dữ liệu duy nhất theo tài liệu mà client giữ.
Hết hạn phiên / CloseDocumentMục bộ nhớ đệm bị xóa sau thời gian chờ hoặc khi đóng rõ ràng.Không có tài nguyên tồn đọng trong dịch vụ Viewer.

Vì dịch vụ tự nó không bao giờ lưu trữ dữ liệu tài liệu, bạn có thể an toàn mở rộng web farm, thay thế các node, hoặc khởi động lại ứng dụng mà không mất bất kỳ trạng thái nào mà người dùng nhìn thấy — chỉ token sẽ trở nên không hợp lệ, buộc client mở lại tài liệu.


Triển khai Viewer không trạng thái trong ứng dụng của bạn

  1. Thêm AddDoconut, AddSession, và một nhà cung cấp bộ nhớ đệm vào Program.cs.
  2. Dán đoạn mã open‑endpoint vào cấu hình minimal‑API của bạn.
  3. Chuyển token đã trả về cho objViewer.View(token) ở phía front‑end.

Bây giờ bạn đã có một API mở tài liệu hoàn toàn không trạng thái, sẵn sàng cho môi trường sản xuất, tận dụng thiết kế Viewer của Doconut.

#dotnet8#viewer#stateless#api#doconut