Início Rápido

Renderize seu primeiro documento em MVC 5 ou Web Forms

Este tutorial leva uma aplicação ASP.NET no .NET Framework 4.7.2 de um pacote instalado a um documento renderizado no navegador: Global.asax, um endpoint de abertura, os recursos do visualizador, o widget e o token que os conecta. Assume‑se que os registros no Web.config de Instalação estejam em vigor — sem o handler DocImage.axd e o módulo de recursos, nada abaixo pode alcançar o servidor.

Compose Doconut no Global.asax

Um Application_Start completo para uma aplicação MVC 5:

csharp
// Global.asax.cs - compose uma vez por processo de trabalho, libere no desligamento.
protected void Application_Start()
{
    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

    Doconut.DoconutHost.Initialize(options =>
    {
        options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
        options.UnsafeMode  = false; // uma página é servida apenas para a sessão que abriu o documento
    });

    // Apenas MVC: mantenha os dois endpoints Doconut fora do roteamento.
    RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    RouteTable.Routes.IgnoreRoute("doconut-res/{*pathInfo}");
}

protected void Application_End()
{
    Doconut.DoconutHost.Shutdown();
}
  • Encoding.RegisterProvider torna as páginas de código legadas que alguns formatos de documento utilizam disponíveis ao processo. Chame‑o uma vez, antes que o primeiro documento seja aberto.
  • UnsafeMode = false é o padrão, escrito explicitamente para que ninguém o altere acidentalmente: DocImage.axd serve uma página apenas para a sessão ASP.NET que abriu o documento.
  • As duas chamadas IgnoreRoute mantêm o roteamento MVC afastado de DocImage.axd e /doconut-res/*, que são servidos pelo handler e pelo módulo. Uma aplicação Web Forms não possui rotas MVC e não precisa de nenhuma dessas linhas.
  • DoconutHost.Shutdown interrompe o trabalho em segundo plano do Doconut e libera seus serviços quando o pool de aplicações é reciclado. É seguro chamar mesmo se Initialize nunca foi executado.

Abra um documento

Abrir um documento retorna um token opaco. O widget envia esse token em cada solicitação de página.

No MVC 5, uma ação de controller resolve o serviço Viewer a partir de DoconutHost.Services — o MVC 5 não possui injeção de dependência via construtor para ele:

csharp
// POST /Document/Open
[HttpPost]
public async Task<ActionResult> Open()
{
    var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();

    // O token é opaco - entregue‑o ao visualizador, nunca registre ou persista‑o.
    string token = await viewer.OpenDocumentAsync(Server.MapPath("~/files/Sample.pdf"));
    return Json(new { token });
}

O documento deve ser aberto dentro de uma requisição que possua estado de sessão, pois ao abri‑lo concede à sessão ASP.NET atual acesso às suas páginas. Controllers MVC e páginas Web Forms possuem estado de sessão por padrão. Um IHttpHandler personalizado não possui, a menos que implemente System.Web.SessionState.IRequiresSessionState. Abra um documento a partir de um handler sem isso, e o visualizador exibirá “Você não está autorizado a visualizar esta página.” em cada página.

No Web Forms, a própria página pode abrir o documento em seu code-behind. OpenDocument é a forma síncrona de OpenDocumentAsync, destinada a code-behind que não utiliza páginas assíncronas:

csharp
// Default.aspx.cs
protected string Token;

protected void Page_Load(object sender, EventArgs e)
{
    var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();
    Token = viewer.OpenDocument(Server.MapPath("~/files/Sample.pdf"));
}

Trate o token como uma credencial de portador: nunca o registre ou persista; entregue‑o apenas ao widget. Ele deixa de funcionar quando a sessão do documento expira — abra o documento novamente para obter um novo.

Referencie os recursos do visualizador

Viewer.ReferenceCss e Viewer.ReferenceScripts emitem as tags <link> e <script> para os recursos incorporados, na ordem de dependência, apontando para /doconut-res/. O widget é um plugin jQuery, portanto o jQuery vem primeiro.

MVC 5. As visualizações não têm @inject, então produza as tags no controlador e passe‑as via ViewBag:

csharp
public ActionResult Index()
{
    var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();
    ViewBag.ViewerCss = viewer.ReferenceCss(new CssConfig
    {
        IncludeBootstrapCss = true,
        IncludeViewerCss    = true
    });
    ViewBag.ViewerScripts = viewer.ReferenceScripts(new ScriptConfig
    {
        IncludeJQuery        = true,
        IncludeBootstrap     = true,
        IncludeViewerScripts = true
    });
    return View();
}
html
@Html.Raw(ViewBag.ViewerCss)
...
@Html.Raw(ViewBag.ViewerScripts)

Mantenha esse trabalho no controlador. O MVC 5 compila as visualizações quando são servidas pela primeira vez e, sem um pacote de compilador extra, esse compilador entende apenas C# 5 — sem ?., sem $"...", sem nameof. Uma visualização que os utiliza compila corretamente no Visual Studio, mas devolve um 500 vazio no navegador.

Web Forms. Exponha as mesmas strings do code‑behind e escreva‑as com <%= %>:

html
<head>
    <%= ViewerCss %>
</head>
<body>
    ...
    <%= ViewerScripts %>
</body>

IncludeViewerCss e IncludeViewerScripts são o núcleo obrigatório. Para adicionar as faixas de Busca e Anotação, também defina IncludeSearchCss, IncludeAnnotationCss, IncludeSearchScripts, IncludeSearchBar, IncludeAnnotationScripts e IncludeAnnotationBar. Ambos os métodos omitem os arquivos de uma faixa quando a licença não concede essa capacidade; o visualizador ainda inicia.

Adicione o visualizador a uma página

A superfície de renderização são dois divs aninhados:

html
<div id="divDocViewer">
    <div id="div_ctlDoc"></div>
</div>

Dê ao div externo uma altura real — o visualizador preenche seu contêiner e o mede ao iniciar. O visualizador não desenha sua própria barra de ferramentas: GotoPage, Next, Zoom, FitType e o restante são métodos que sua página conecta a seus próprios botões, posicionados ao lado do visualizador:

html
<nav id="toolbar" aria-label="Document viewer controls">
    <button type="button" onclick="objViewer.GotoPage(1)">First</button>
    <button type="button" onclick="objViewer.Next(false)">Previous</button>
    <button type="button" onclick="objViewer.Next(true)">Next</button>
    <button type="button" onclick="objViewer.Zoom(false)">Zoom out</button>
    <button type="button" onclick="objViewer.Zoom(true)">Zoom in</button>
    <button type="button" onclick="objViewer.FitType('width')">Fit width</button>
</nav>

Inicialize o visualizador e mostre o documento

Depois dos scripts do visualizador, crie o widget e, em seguida, forneça‑le o token:

javascript
var objViewer = $('#div_ctlDoc').docViewer({
    showThumbs: true,
    autoLoad:   false,
    pageZoom:   100,
    FitType:    'width',
    BasePath:   '/',                   // '/' significa DocImage.axd na raiz do site
    ResPath:    'doconut-res/images',  // sem '/' inicial
    onViewerReady: function () {
        // as páginas estão visíveis; oculte um indicador de carregamento aqui
    },
    onError: function (message) {
        console.error('Doconut viewer error:', message);
    }
});

fetch('/Document/Open', { method: 'POST' })
    .then(function (resp) { return resp.json(); })
    .then(function (data) { objViewer.View(data.token); });

No Web Forms, onde a página abre o documento por conta própria, as três últimas linhas tornam‑se objViewer.View('<%= Token %>');.

Quatro detalhes aqui falham sem uma mensagem de erro:

  • BasePath: '/' aponta para DocImage.axd na raiz do site. Para uma aplicação em um diretório virtual, use seu nome sem barras ('myapp' solicita /myapp/DocImage.axd). Uma barra inicial ('/myapp') produz //myapp/DocImage.axd, que o navegador interpreta como uma requisição para outro host.
  • ResPath: 'doconut-res/images' — os ícones ficam uma pasta abaixo da raiz de recursos. Com 'doconut-res', cada ícone retorna 404: sem glifos da barra de ferramentas e sem spinner de carregamento, embora o documento ainda seja renderizado. Uma barra inicial o quebra da mesma forma que BasePath.
  • Callbacks são opções. onViewerReady, onError e os demais vão no objeto passado para docViewer(...). Uma função global nomeada após o visualizador, como ctlDoc_ViewerReady, nunca é chamada.
  • Mantenha o visualizador, então chame View separadamente. docViewer(...) devolve o objeto com Zoom, Next e FitType; View(...) devolve outra coisa. var objViewer = $('#div_ctlDoc').docViewer({...}).View(token) renderiza o documento, mas falha com objViewer.Zoom is not a function no primeiro clique da barra de ferramentas.

Os nomes das opções misturam camelCase (showThumbs, autoLoad, pageZoom) e PascalCase (FitType, BasePath, ResPath). Uma opção escrita incorretamente é ignorada, e o widget usa o padrão.

A alternativa de uma linha

Para uma página que só precisa exibir um documento, sem uma barra de ferramentas própria, Viewer.RenderViewer gera todo o script de inicialização — docViewer(...) com BasePath: '/' e ResPath: 'doconut-res/images', então .View(token). Ele existe apenas neste pacote:

csharp
// Código-behind do Web Forms, após abrir o documento
ViewerInit = viewer.RenderViewer("div_ctlDoc", Token);
html
<div id="div_ctlDoc" style="height: 100vh"></div>
<%= ViewerScripts %>
<%= ViewerInit %>

Passe um ViewerConfig como terceiro argumento para alterar o zoom, o ajuste ou o painel de miniaturas. Como o script gerado não mantém referência ao visualizador, use a inicialização escrita à mão acima quando sua página precisar de sua própria barra de ferramentas.

Fechar o documento

Chame objViewer.Close(true) quando o usuário sair do visualizador ou abrir um substituto: ele limpa o widget e envia uma solicitação de fechamento para DocImage.axd. objViewer.Close() sem argumento limpa apenas o widget. No servidor, viewer.CloseDocument(token) remove a sessão do documento imediatamente, libera seus recursos de renderização e revoga o acesso da sessão às suas páginas. A expiração deslizante acaba fazendo o mesmo, mas fechar documentos grandes explicitamente libera memória mais cedo.

Executar

Coloque um PDF em ~/files/Sample.pdf, inicie o site no IIS Express (F5 no Visual Studio) e abra a página que hospeda o widget. A primeira página é renderizada, com miniaturas à esquerda. Se não acontecer, veja Solução de Problemas.

O que você obtém sem licença

A falta de licença não gera erro. O visualizador renderiza normalmente, mas cada página exibe uma marca d'água de avaliação. Veja Configuração de Licença para saber onde o Doconut procura sua licença.

Esta página foi útil?