
Tutorial: Abrir Documentos com o Visualizador Doconut Injetado no .NET 8
Introdução
Exemplos mais antigos do Doconut podem construir Viewer diretamente com argumentos de cache, contexto HTTP e caminho da licença. Esse não é o modelo de integração atual do .NET 8. AddDoconut() registra Viewer com injeção de dependência, e os pontos de extremidade da aplicação recebem o serviço em vez de chamar um construtor.

Este tutorial segue o fluxo de requisição atual: registrar serviços e middleware, emitir os recursos do visualizador incorporado, abrir um documento com OpenDocumentAsync, devolver um token de sessão opaco e passar esse token para o widget do navegador.
1. Instalar e registrar Doconut
Adicione o pacote .NET 8:
dotnet add package Doconut.NET8
Registre Doconut e os serviços de sessão do ASP.NET:
builder.Services.AddDoconut(options =>
{
options.LicensePath = "Doconut.Viewer.lic";
options.MiddlewarePath = "/doconut";
options.ResourcesPath = "/doconut-res";
options.UnsafeMode = false;
});
builder.Services.AddSession();
Encadeie o middleware na ordem necessária. O middleware de recursos deve ser executado antes do middleware terminal de documentos:
app.UseRouting();
app.UseSession();
app.UseDoconutResources();
app.Map("/doconut", branch => branch.UseDoconut());
MiddlewarePath coordena a configuração, mas não cria o ramo ASP.NET por si só. O caminho mapeado /doconut deve coincidir com o BasePath do widget.
2. Adicionar a superfície do visualizador e os recursos
O visualizador de navegador Doconut é um plugin jQuery. Em uma página Razor, injete Viewer e peça que ele emita as tags de recurso na ordem de dependência:
@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>
Inicialize o widget com caminhos que correspondam ao registro no 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);
}
});
A capitalização das opções é significativa. Use os nomes mostrados pela versão instalada em vez de normalizá‑los para um único estilo.
3. Injetar Viewer e abrir um documento
Viewer é registrado como um serviço transitório. Resolva‑o por injeção de ponto de extremidade, injeção de construtor ou a facilidade equivalente na sua aplicação 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 um upload, forneça um stream e um FileInfo cuja extensão identifique o formato de origem:
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 });
});
Valide o tamanho do upload, a extensão e a autorização antes de abrir conteúdo fornecido pelo usuário. Não converta o nome de arquivo enviado em um caminho de servidor.
4. Passar o token para o widget
Recupere o ponto de extremidade de abertura e entregue o token retornado ao 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));
Trate o token como credencial de portador para uma sessão de documento ao vivo:
- Não registre nem persista‑o.
- Retorne‑o apenas a um cliente autorizado.
- Não exponha o caminho do arquivo fonte.
- Reabra o documento quando a sessão expirar.
- Feche a sessão quando o documento não for mais necessário.
5. Fechar sessões do lado do servidor deliberadamente
O código cliente pode chamar objViewer.Close() quando o usuário sai do visualizador. Fluxos de trabalho no servidor também podem revogar um token conhecido explicitamente:
app.MapPost("/api/close", (string token, Viewer viewer) =>
{
viewer.CloseDocument(token);
return Results.NoContent();
});
O fechamento explícito é especialmente útil para documentos grandes. A expiração da sessão permanece como fallback, não como substituto para um gerenciamento previsível do ciclo de vida da aplicação.
6. Adicionar módulos opcionais somente depois que o núcleo funcionar
Busca e anotações se ligam ao mesmo visualizador já inicializado. Adicione seus CSS, scripts, montagens, verificações de licença e callbacks de ciclo de vida apenas depois que o fluxo básico for bem‑sucedido:
AddDoconut + session services
-> UseSession
-> UseDoconutResources
-> mapped UseDoconut branch
-> viewer resources and mount
-> initialize docViewer
-> OpenDocumentAsync
-> objViewer.View(token)
Essa ordem mantém falhas de renderização do núcleo separadas da configuração de módulos opcionais.
Erros comuns de migração
| Padrão antigo ou incorreto | Direção atual do .NET 8 |
|---|---|
new Viewer(cache, accessor, licensePath) | Injetar Viewer após AddDoconut() |
| Chamadas estáticas de carregamento de licença no código de requisição | Configurar a entrada da licença em AddDoconut() |
Exemplos síncronos de OpenDocument(...) | Usar OpenDocumentAsync(...) |
| CDN externo ou inventado para o visualizador | Emitir recursos incorporados com ReferenceCss e ReferenceScripts |
API JavaScript genérica init() | Inicializar $('#div_ctlDoc').docViewer(...) |
| Persistir o token do visualizador | Persistir seu ID de documento; tratar o token como temporário |
Use a documentação do Doconut oficial e verifique os exemplos contra a versão do pacote instalado antes de adaptá‑los ao código de produção.