
Tutorial: Abrir documentos con el visor Doconut inyectado en .NET 8
Introducción
Los ejemplos más antiguos de Doconut pueden construir Viewer directamente con argumentos de caché, contexto HTTP y ruta de licencia. Ese no es el modelo de integración actual de .NET 8. AddDoconut() registra Viewer mediante inyección de dependencias, y los puntos finales de la aplicación reciben el servicio en lugar de llamar a un constructor.

Este tutorial sigue el flujo de solicitud actual: registrar servicios y middleware, emitir los recursos del visor incrustados, abrir un documento con OpenDocumentAsync, devolver un token de sesión opaco y pasar ese token al widget del navegador.
1. Instalar y registrar Doconut
Agrega el paquete .NET 8:
dotnet add package Doconut.NET8
Registra Doconut y los servicios de sesión de ASP.NET:
builder.Services.AddDoconut(options =>
{
options.LicensePath = "Doconut.Viewer.lic";
options.MiddlewarePath = "/doconut";
options.ResourcesPath = "/doconut-res";
options.UnsafeMode = false;
});
builder.Services.AddSession();
Conecta el middleware en el orden requerido. El middleware de recursos debe ejecutarse antes del middleware terminal de documentos:
app.UseRouting();
app.UseSession();
app.UseDoconutResources();
app.Map("/doconut", branch => branch.UseDoconut());
MiddlewarePath coordina la configuración pero no crea la rama de ASP.NET por sí mismo. La ruta mapeada /doconut debe coincidir con el BasePath del widget.
2. Añadir la superficie del visor y los recursos
El visor de navegador Doconut es un plugin jQuery. En una página Razor, inyecta Viewer y pídele que emita las etiquetas de recursos en orden de dependencia:
@inject Doconut.Viewer Viewer
@Html.Raw(Viewer.ReferenceCss(new CssConfig
{
IncludeViewerCss = true
}))
@Html.Raw(Viewer.ReferenceScripts(new ScriptConfig
{
IncludeJQuery = true,
IncludeViewerScripts = true
}))
<div id="divDocViewer">
<div id="div_ctlDoc"></div>
</div>
Inicializa el widget con rutas que coincidan con el registro del servidor:
const objViewer = $('#div_ctlDoc').docViewer({
showThumbs: true,
autoLoad: false,
pageZoom: 100,
FitType: 'width',
BasePath: '/doconut',
ResPath: '/doconut-res/images',
onError: function (message) {
console.error('Doconut viewer error:', message);
}
});
El uso de mayúsculas en las opciones es significativo. Utiliza los nombres mostrados por la versión instalada en lugar de normalizarlos a un único estilo.
3. Inyectar Viewer y abrir un documento
Viewer se registra como un servicio transitorio. Resuélvelo mediante inyección en el punto final, inyección de constructor o la facilidad equivalente en tu aplicación ASP.NET Core.
app.MapPost("/api/open", async (
Viewer viewer,
CancellationToken ct) =>
{
string token = await viewer.OpenDocumentAsync(
"wwwroot/files/Sample.pdf",
ct: ct);
return Results.Ok(new { token });
});
Para una carga, proporciona un flujo y un FileInfo cuya extensión identifique el formato de origen:
app.MapPost("/api/open-upload", async (
IFormFile file,
Viewer viewer,
CancellationToken ct) =>
{
await using var stream = file.OpenReadStream();
string token = await viewer.OpenDocumentAsync(
stream,
new FileInfo(file.FileName),
ct: ct);
return Results.Ok(new { token });
});
Valida el tamaño de la carga, la extensión y la autorización antes de abrir contenido suministrado por el usuario. No conviertas el nombre de archivo enviado en una ruta del servidor.
4. Pasar el token al widget
Obtén el punto final de apertura y entrega el token devuelto a objViewer.View:
fetch('/api/open', { method: 'POST' })
.then(response => {
if (!response.ok) throw new Error('The document could not be opened.');
return response.json();
})
.then(data => objViewer.View(data.token))
.catch(error => console.error(error));
Trata el token como una credencial portadora para una sesión de documento en vivo:
- No lo registres ni lo persistas.
- Devuélvelo solo a un cliente autorizado.
- No expongas la ruta del archivo fuente.
- Vuelve a abrir el documento cuando una sesión expire.
- Cierra la sesión cuando el documento ya no sea necesario.
5. Cerrar sesiones del lado del servidor de forma deliberada
El código cliente puede llamar a objViewer.Close() cuando el usuario abandona el visor. Los flujos de trabajo del servidor también pueden revocar un token conocido explícitamente:
app.MapPost("/api/close", (string token, Viewer viewer) =>
{
viewer.CloseDocument(token);
return Results.NoContent();
});
El cierre explícito es especialmente útil para documentos grandes. La expiración de la sesión sigue siendo un mecanismo de respaldo, no un sustituto de una gestión predecible del ciclo de vida de la aplicación.
6. Añadir módulos opcionales solo después de que el núcleo funcione
La búsqueda y las anotaciones se adjuntan al mismo visor inicializado. Añade sus CSS, scripts, montajes, verificaciones de licencia y callbacks de ciclo de vida solo después de que el flujo base tenga éxito:
AddDoconut + session services
-> UseSession
-> UseDoconutResources
-> mapped UseDoconut branch
-> viewer resources and mount
-> initialize docViewer
-> OpenDocumentAsync
-> objViewer.View(token)
Este orden mantiene los fallos de renderizado del núcleo separados de la configuración de módulos opcionales.
Errores comunes de migración
| Patrón antiguo o incorrecto | Dirección actual de .NET 8 |
|---|---|
new Viewer(cache, accessor, licensePath) | Inyectar Viewer después de AddDoconut() |
| Llamadas estáticas de carga de licencia en el código de solicitud | Configurar la entrada de licencia en AddDoconut() |
Ejemplos síncronos de OpenDocument(...) | Usar OpenDocumentAsync(...) |
| Un CDN externo o inventado para el visor | Emitir recursos incrustados con ReferenceCss y ReferenceScripts |
API genérica de JavaScript init() | Inicializar $('#div_ctlDoc').docViewer(...) |
| Persistir el token del visor | Persistir tu ID de documento; tratar el token como temporal |
Utiliza la documentación oficial de documentación de Doconut y verifica los ejemplos contra la versión del paquete instalado antes de adaptarlos a código de producción.