
Construye un Visor Seguro de Gestión de Documentos en .NET con Doconut
Implementando la Gestión de Documentos con Doconut
Un flujo de gestión de documentos en un portal .NET normalmente necesita tres cosas:
- Una forma de cargar PDFs, archivos de Office, dibujos CAD o imágenes sin escribir un visor desde cero.
- Un token seguro que vincula el documento cargado a la sesión actual del navegador.
- Un paso de limpieza que libera la memoria tan pronto como el usuario termina.
Doconut proporciona los tres a través de un único servicio Viewer, una sesión ligera IMemoryCache y llamadas explícitas CloseDocument.
1. Registrar el visor en el contenedor DI
Durante el inicio de la aplicación, agrega los servicios Doconut al contenedor DI llamando al método de registro de Doconut descrito en la documentación oficial. Este paso registra el visor, la gestión de licencias y la caché en memoria que almacenará las sesiones de documentos.
El registro valida la licencia al iniciar, por lo que cualquier licencia faltante o inválida falla rápidamente y conoces el problema antes de que la primera solicitud llegue al servidor.
2. Insertar el middleware que sirve imágenes de página, miniaturas y datos de anotaciones
Configura el middleware Doconut en la canalización de solicitudes para que cualquier petición que contenga una cadena de consulta ?token= sea manejada por Doconut. El middleware aplica el marcador de seguridad predeterminado (secure-{token}) cuando UnsafeMode es false (el valor predeterminado) y sirve imágenes de página, miniaturas y datos de anotaciones.
Colocar el middleware en una rama dedicada mantiene el resto de tu canalización sin tocar y permite el escalado horizontal sin sesiones pegajosas.
3. Abrir un documento y obtener el token de sesión opaco
Crea un único punto de entrada que reciba una ruta de archivo (o un flujo) y devuelva el token. El token es la única credencial que el widget cliente ve.
app.MapPost("/api/open", async (Viewer viewer) =>
{
// El token es opaco — pásalo al widget, nunca lo registres ni lo persistas.
string token = await viewer.OpenDocumentAsync("wwwroot/files/Contract.pdf");
return Results.Ok(new { token });
});
Qué ocurre dentro de OpenDocumentAsync
- Control de licencia – una licencia inválida lanza
LicenseExceptioninmediatamente. - Creación de sesión – Doconut elige el visor de formato correcto (PDF, Word, DWG, …) y almacena el motor en
IMemoryCachebajo un token GUID. - Registro de seguridad – con
UnsafeMode = falseel token se vincula a la sesión ASP.NET del llamador mediante un marcadorsecure-{token}. Sólo esa sesión del navegador puede solicitar páginas. - Devolución del token – el cliente recibe el token y lo usa para cada solicitud posterior (
/DocImage.axd?token=…).
La expiración deslizante predeterminada es de 60 minutos (configurable a través de DocOptions.TimeOut). Cada solicitud de página reinicia el temporizador, por lo que las sesiones inactivas desaparecen automáticamente.
4. Renderizar el documento del lado del cliente
Desde el navegador llamas al punto de entrada, obtienes el token y lo entregas al widget Doconut:
fetch('/api/open', { method: 'POST' })
.then(r => r.json())
.then(d => {
const token = d.token;
objViewer.View(token); // Widget JavaScript suministrado por Doconut
});
El widget internamente emite solicitudes de página, miniatura, búsqueda y anotación que todas incluyen el mismo token. Debido a que el token está vinculado a la sesión del lado del servidor, un usuario malintencionado no puede secuestrar el documento de otro usuario.
5. Cerrar el documento tan pronto como el usuario abandone el visor
Para PDFs o archivos CAD grandes deberías liberar el motor de renderizado inmediatamente. Llama a CloseDocument desde un punto de entrada del lado del servidor o desde el evento “unload” del widget.
// Endpoint del lado del servidor
app.MapPost("/api/close", (Viewer viewer, string token) =>
{
viewer.CloseDocument(token);
return Results.Ok();
});
// Llamada directa desde el widget (si expones el token al backend)
viewer.CloseDocument(token);
CloseDocument elimina la sesión de la caché, dispone del motor de documento subyacente, borra el marcador secure-{token} y revoca la concesión de acceso. La expiración deslizante eventualmente haría lo mismo, pero un cierre explícito garantiza que la memoria se recupere en el instante en que el usuario termina.
6. Opcional: Convertir un documento en el servidor
Si tu flujo de trabajo requiere una exportación a PDF de un archivo Word cargado, habilita el plugin Converter en la configuración de Doconut (ver documentación). Después de registrar el plugin puedes inyectar DocumentConverter y llamar a su método ConvertAsync. La conversión se ejecuta en el servidor, por lo que nunca necesitas Office instalado en el servidor web.
7. Consideraciones de escalado para la gestión de documentos de nivel empresarial
- Front‑ends sin estado – El widget del visor nunca almacena datos del documento; todo el procesamiento pesado permanece en el servidor.
- Caché distribuida – Reemplaza la caché en memoria predeterminada con un proveedor distribuido (Redis, NCache) si ejecutas varios nodos de granja web. El mapeo token‑a‑sesión funciona sin cambios porque el middleware lee de la
IMemoryCacheconfigurada. - Trabajos en segundo plano – Puedes preabrir documentos en un trabajador en segundo plano, almacenar el token en caché y entregarlo a la UI más tarde. Solo recuerda que cada token es de uso único por sesión; reutilizar requiere una nueva llamada
OpenDocumentAsync.
Estos patrones te permiten construir una plataforma de gestión de documentos que escala desde un portal intranet de un solo servidor hasta un servicio en la nube multi‑región sin reescribir la lógica del visor.
8. Lista de verificación rápida para una implementación lista para producción
| Paso | Acción |
|---|---|
| 1 | Registrar los servicios Doconut en Program.cs (validar licencia). |
| 2 | Añadir el middleware Doconut en una rama dedicada. |
| 3 | Exponer un punto de entrada /api/open que llame a OpenDocumentAsync. |
| 4 | Pasar el token devuelto a objViewer.View(token) en el cliente. |
| 5 | Llamar a CloseDocument(token) cuando el visor esté oculto o la página se descargue. |
| 6 | (Opcional) Habilitar ConverterPlugin si necesitas conversión del lado del servidor. |
| 7 | (Opcional) Cambiar IMemoryCache por una caché distribuida para escalado horizontal. |
Sigue la lista y tendrás un flujo completo, seguro y de alto rendimiento de gestión de documentos construido sobre el visor nativo .NET de Doconut.