
El Visor es Sin Estado — Cómo Construir un Punto de Extremo Abierto Minimal en .NET 8
El Visor es Sin Estado — por Diseño
Viewer no mantiene datos de documento por solicitud. Es una clase sellada, nunca implementa IDisposable, y cada documento que abres vive en una sesión separada que la caché del framework gestiona. Por eso puedes inyectar una única instancia Viewer en cualquier parte de tu aplicación ASP.NET Core y llamarla de forma segura desde muchas solicitudes concurrentes.
Consecuencias de un servicio sin estado
- Sin recursos ocultos – el propio servicio nunca asigna búferes grandes que requieran limpieza explícita.
- Seguridad de subprocesos por defecto – porque no se almacena estado específico de la solicitud, la misma instancia
Viewerpuede ser usada por varios hilos sin bloqueos. - Despliegues escalables – el escalado horizontal funciona listo para usar; no necesitas sesiones pegajosas ni afinidad de servidor, solo el token de sesión que posee el cliente.
Toda la información específica del documento (páginas, anotaciones, índice de búsqueda) se mantiene en una sesión creada por OpenDocumentAsync. La sesión se almacena en IMemoryCache (o cualquier IDistributedCache que configures) y expira automáticamente después de un período de inactividad (60 minutos por defecto). Cuando termines puedes llamar a CloseDocument para liberar la entrada de caché anticipadamente.
Registrando el Visor sin estado
Debido a que Viewer no tiene estado mutable, regístralo una sola vez durante el arranque:
builder.Services.AddDoconut(); // registra Viewer y el middleware requerido
builder.Services.AddSession(); // requerido para la seguridad del token
builder.Services.AddDistributedMemoryCache(); // caché simple para la demo
La llamada AddDoconut también conecta el middleware que sirve los recursos estáticos del visor. Después de que los servicios estén configurados, puedes solicitar Viewer en cualquier firma de punto de extremo.
Punto de extremo minimalista para abrir documento (ejemplo net‑8)
El siguiente código es el fragmento exacto de la documentación oficial y funciona listo para usar en un proyecto .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");
});
Qué hace el código
- Acepta un nombre de archivo – el cliente indica al servidor qué archivo bajo
wwwroot/filesabrir. - Llama a
OpenDocumentAsync– elViewersin estado crea una nueva sesión, la almacena en la caché y devuelve un token opaco. - Devuelve el token como texto plano – el cliente recibe solo el token; el servidor nunca envía los bytes del documento en esta respuesta.
Debido a que Viewer no contiene datos del documento, el punto de extremo no necesita bloques using, llamadas Dispose, ni fábricas por solicitud. El token es la única credencial que el cliente enviará de vuelta al widget del visor (objViewer.View(token) en el front‑end).
Usando el token en el lado del cliente
Después de que el token es devuelto, el widget del front‑end llama a objViewer.View(token). El widget entonces incluye el mismo token en cada solicitud posterior para imágenes de página, búsquedas o acciones de anotación. El servidor valida el token contra la sesión que originalmente abrió el documento. Si el token se presenta desde una sesión de navegador diferente, el visor devuelve un error de autorización, que es el comportamiento de seguridad previsto.
Cerrando una sesión anticipadamente (opcional)
Si tu flujo de trabajo sabe que un documento nunca será accedido nuevamente, puedes liberar la entrada de caché invocando CloseDocument en el Viewer. Esto elimina la sesión de la caché y evita que el temporizador de expiración deslizante la mantenga viva.
Recapitulación del flujo sin estado
| Paso | Qué ocurre | Dónde vive el estado |
|---|---|---|
| Inyectar Visor | Se crea una única instancia Viewer al iniciar. | En el contenedor DI (singleton). |
| OpenDocumentAsync | Licencia verificada → sesión creada → token devuelto. | Sesión almacenada en IMemoryCache (o caché distribuida). |
| Cliente renderiza | El widget envía el token con cada solicitud. | El token es el único dato por‑documento que posee el cliente. |
| Expiración de sesión / CloseDocument | Entrada de caché eliminada tras tiempo de espera o cierre explícito. | No quedan recursos pendientes en el servicio del Visor. |
Debido a que el propio servicio nunca almacena datos del documento, puedes escalar de forma segura tu granja web, reemplazar nodos o reiniciar la aplicación sin perder ningún estado visible para el usuario—solo el token se invalida, lo que obliga al cliente a volver a abrir el documento.
Desplegando el Visor sin estado en tu aplicación
- Añade
AddDoconut,AddSessiony un proveedor de caché aProgram.cs. - Pega el fragmento del punto de extremo abierto en tu configuración minimal‑API.
- Pasa el token devuelto a
objViewer.View(token)en el front‑end.
Ahora tienes una API de apertura de documentos totalmente sin estado y lista para producción que aprovecha el diseño Viewer de Doconut.