Avvio Rapido

Visualizza il tuo primo documento in pochi minuti

Questo tutorial porta un'app ASP.NET Core da un Program.cs vuoto a un documento visualizzato nel browser: registrazione del server, pacchetto completo Viewer (toolbar Viewer, mount Viewer e nastri opzionali di Ricerca/Annotazione), riferimenti alle risorse, inizializzazione client, apertura del documento ed esecuzione.

Configurazione del server

AddDoconut() registra i servizi; UseDoconutResources() e UseDoconut() collegano il middleware. La chiamata alle risorse deve avvenire per prima. Le chiamate alla sessione sono richieste anch'esse — la sicurezza predefinita dei documenti Doconut convalida ogni richiesta di pagina contro lo stato della sessione ASP.NET. Hai già registrato Doconut durante l'Installazione? Salta alla sezione successiva.

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
});
builder.Services.AddSession(); // Doconut document security rides on ASP.NET session state

app.UseSession();          // call UseSession() before UseDoconut()
app.UseDoconutResources(); // must be registered before UseDoconut()
app.UseDoconut();

Per un layout di percorso in stile produzione, mappa il middleware dei documenti a un ramo esplicito e mantieni allineate le quattro impostazioni di percorso:

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = Path.Combine(AppContext.BaseDirectory, "Doconut.Viewer.lic");
    options.MiddlewarePath = "/doconut";
    options.ResourcesPath = "/doconut-res";
    options.UnsafeMode = false;
});
builder.Services.AddSession();

app.UseRouting();
app.UseSession();
app.UseDoconutResources();
app.Map("/doconut", branch => branch.UseDoconut());

MiddlewarePath è un valore di coordinazione; non mappa un ramo ASP.NET Core da solo. In questo esempio l'host mappa /doconut, quindi il client deve usare BasePath: '/doconut'. ResourcesPath serve il bundle incorporato su /doconut-res, e il percorso delle risorse immagine del widget è quindi ResPath: '/doconut-res/images'.

Aggiungi il viewer a una pagina

Il Viewer è il nucleo richiesto della pagina. La sua superficie di rendering utilizza due div nidificati:

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

Considera la toolbar, i mount dei moduli e la superficie del Viewer come una singola composizione di pagina. Ricerca e Annotazione inseriscono i loro nastri incorporati nei mount opzionali, ma quei moduli non sono mai autonomi: si collegano sempre al Viewer nella stessa pagina. Usa lo stesso ordine di Doconut.TestApp e Doconut.TestApp.Distributed:

html
<nav id="toolbar" aria-label="Document viewer controls">
    <!-- Viewer navigation, zoom, Search, and Annotation buttons -->
</nav>

<div id="searchBarMount"></div>
<div id="annBarMount"></div>

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

Riferisci le risorse del viewer

In una vista Razor, il servizio Viewer iniettato emette i tag <link> e <script> del viewer in ordine di dipendenza — il widget è un plugin jQuery, quindi jQuery deve essere caricato prima degli script del viewer:

html
@inject Doconut.Viewer Viewer

@Html.Raw(Viewer.ReferenceCss(new CssConfig
{
    IncludeBootstrapCss = true,
    IncludeViewerCss    = true
}))

@Html.Raw(Viewer.ReferenceScripts(new ScriptConfig
{
    IncludeJQuery        = true,
    IncludeBootstrap     = true,
    IncludeViewerScripts = true
}))

Per il pacchetto Viewer completo, richiedi le risorse del Viewer e dei moduli insieme:

html
@Html.Raw(Viewer.ReferenceCss(new CssConfig
{
    IncludeBootstrapCss  = true,
    IncludeViewerCss     = true,
    IncludeSearchCss     = true,
    IncludeAnnotationCss = true
}))

@Html.Raw(Viewer.ReferenceScripts(new ScriptConfig
{
    IncludeJQuery             = true,
    IncludeBootstrap         = true,
    IncludeViewerScripts     = true,
    IncludeSearchScripts     = true,
    IncludeSearchBar         = true,
    IncludeAnnotationScripts = true,
    IncludeAnnotationBar     = true
}))

IncludeViewerCss e IncludeViewerScripts sono le flag obbligatorie del core. Non pubblicare mai un esempio di Nastro di Ricerca o Annotazione senza di esse, il mount del Viewer e un'istanza docViewer. ReferenceCss e ReferenceScripts omettono le risorse di un modulo opzionale quando la licenza corrente non concede tale capacità; il core Viewer si avvia comunque.

Inizializza il viewer

Il widget client‑side è un plugin jQuery. Questo è un set minimale di opzioni di inizializzazione reali (non pseudocodice):

javascript
let searchBar = null;
let annBar = null;

const objViewer = $('#div_ctlDoc').docViewer({
    showThumbs: true,
    autoLoad:   false,
    pageZoom:   100,
    FitType:    'width',
    BasePath:   '/doconut',
    ResPath:    '/doconut-res/images',
    onViewerReady: function () {
        // pages are visible; safe to hide a loading spinner here
    },
    // Forward annotation lifecycle events to the embedded ribbon when it is present.
    onAnnLoaded:    () => annBar?.handleAnnLoaded(),
    onAnnSaved:     () => annBar?.handleAnnSaved(),
    onAnnSaveError: () => annBar?.handleAnnSaveError(),
    onAnnClosed:    () => annBar?.handleAnnClosed(),
    onError: function (message) {
        console.error('Doconut viewer error:', message);
    }
});

Il caso delle lettere delle opzioni è davvero misto — showThumbs, autoLoad e pageZoom sono camelCase, ma FitType, BasePath e ResPath sono PascalCase. Non esiste una regola coerente; se sbagli il caso l'opzione viene silenziosamente ignorata (il widget torna al valore predefinito invece di lanciare un errore).

Assembla il pacchetto Viewer completo

Entrambe le applicazioni di riferimento .NET 6 installano le seguenti parti insieme su una pagina:

Parte del pacchettoRequisitoCome è collegata
Risorse del Viewer, mount e objViewerObbligatorioCore document renderer
Toolbar del ViewerObbligatorio nella composizione di riferimentoMarkup host; i pulsanti chiamano lo stesso objViewer
Nastro di RicercaModulo opzionale, con licenzadoconutSearchBar(...).attach(objViewer)
Nastro di AnnotazioneModulo opzionale, con licenzadoconutAnnotationBar(...).attach(objViewer)

Sebbene la toolbar principale del Viewer sia markup host, viene installata insieme al Viewer e non deve mai essere documentata come controllo isolato. Questo mantiene il layout, le etichette, le icone e le regole di autorizzazione sotto il controllo della tua applicazione, mentre ogni pulsante agisce sulla stessa istanza del Viewer:

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.GotoPage(objViewer.TotalPages())">Last</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>
    <button type="button" onclick="objViewer.FitType('height')">Fit height</button>
    <button type="button" id="openSearch">Search</button>
    <button type="button" id="openAnnotations">Annotations</button>
</nav>

La toolbar di riferimento completa copia anche wwwroot/js/viewerToolbar.js nell'app host per rotazione, miniature, stampa, schermo intero, layout e helper di stato dei pulsanti. Carica quel file host dopo Viewer.ReferenceScripts(...). Mantieni l'helper e il suo markup <nav id="toolbar"> insieme quando copi l'implementazione demo completa.

Mantieni l'ordine di inizializzazione del pacchetto usato da entrambe le applicazioni di riferimento:

  1. Emetti CSS per il Viewer e i moduli con licenza.
  2. Renderizza la toolbar del Viewer, i mount di Ricerca/Annotazione e il mount del Viewer insieme.
  3. Emetti script per il Viewer e i moduli con licenza.
  4. Carica viewerToolbar.js dell'app host.
  5. Inizializza docViewer e conserva l'objViewer risultante.
  6. Inizializza ogni nastro di Ricerca o Annotazione con licenza.
  7. Chiama attach(objViewer) su ogni Nastro.
  8. Apri il documento e conserva il suo token per le richieste del Viewer e dei moduli.

Doconut.TestApp.Distributed mantiene esattamente questa composizione UI e lo stesso helper della toolbar del Viewer. Il suo valore di richiesta access aggiuntivo e le impostazioni di retry di rendering asincrono appartengono al trasporto distribuito; non modificano il modo in cui il Viewer, la toolbar o i Nastri sono assemblati.

Le guardie lato server sono importanti: quando una capacità opzionale non è disponibile, il suo script non viene emesso, quindi la funzione plugin jQuery non esiste.

html
<script>
    let currentToken = '';

    const refitViewer = () =>
        requestAnimationFrame(() => objViewer.Refit());

    @if (Viewer.IsSearchEnabled)
    {
        <text>
    searchBar = $('#searchBarMount').doconutSearchBar({
        docId: 'ctlDoc',
        getRequestParams: () => ({ token: currentToken }),
        onLayout: refitViewer
    });
    searchBar.attach(objViewer);
        </text>
    }

    @if (Viewer.IsAnnotationEnabled)
    {
        <text>
    annBar = $('#annBarMount').doconutAnnotationBar({
        docId: 'ctlDoc',
        getRequestParams: () => ({ token: currentToken }),
        onLayout: refitViewer
    });
    annBar.attach(objViewer);
        </text>
    }

    document.getElementById('openSearch').addEventListener('click', () => {
        if (!searchBar) return;
        searchBar.isOpen() ? searchBar.close() : searchBar.open();
    });

    document.getElementById('openAnnotations').addEventListener('click', () => {
        if (!annBar) return;
        annBar.isOpen() ? annBar.close() : annBar.open();
    });
</script>

Entrambi i componenti incorporati generano il proprio DOM del Nastro. Ricerca contiene i gruppi Find, Options e Results. Annotazione contiene gli strumenti di authoring, i controlli di stile, le azioni di salvataggio e le azioni opzionali di esportazione/immagine. Le barre espongono open(), close(), reset() e isOpen(); chiama sempre attach(objViewer) una volta dopo averle create.

L'esempio sopra omette callback host opzionali e endpoint di esportazione/immagine dell'Annotazione per mantenere l'avvio minimale. Vedi la guida alla Ricerca e le Annotazioni per la configurazione completa delle funzionalità specifiche, o i Temi personalizzati per stilizzare o sostituire la toolbar del Viewer di proprietà dell'host.

Apri un documento

Il lato server è un unico endpoint: il servizio Viewer iniettato apre il documento e restituisce un token di sessione.

csharp
app.MapPost("/api/open", async (Viewer viewer) =>
{
    // The token is opaque — hand it to the widget, never log or persist it.
    string token = await viewer.OpenDocumentAsync("wwwroot/files/Sample.pdf");
    return Results.Ok(new { token });
});

Il client recupera quel token e lo passa al widget con objViewer.View(token):

javascript
fetch('/api/open', { method: 'POST' })
    .then(resp => resp.json())
    .then(data => {
        currentToken = data.token;
        objViewer.View(currentToken);
    });

Chiudi il documento

Chiama objViewer.Close() quando l'utente lascia il viewer o apre un documento sostitutivo. Nei flussi guidati dal server, viewer.CloseDocument(token) rimuove immediatamente la sessione cache, libera il motore di rendering, elimina il marcatore di sicurezza e revoca il token. La scadenza scorrevole esegue alla fine la stessa pulizia, ma la chiusura esplicita è consigliata per documenti di grandi dimensioni.

Il flusso di richiesta completato è:

text
AddDoconut + middleware
    -> render CSS/scripts and mount div
    -> initialize docViewer
    -> OpenDocumentAsync
    -> return opaque token
    -> objViewer.View(token)
    -> page/search/annotation requests
    -> Close / CloseDocument

Tratta il token come una credenziale di tipo bearer: non loggarlo mai, non salvarlo mai, consegnalo solo al widget. Identifica una sessione documento attiva sul server e smette di funzionare quando quella sessione scade — riapri il documento per ottenerne uno nuovo.

Esegui l'applicazione

Posiziona un PDF in wwwroot/files/Sample.pdf, esegui dotnet run e apri la pagina che ospita il widget. La prima pagina viene visualizzata nel viewer, con un pannello di miniature a sinistra. Se ciò non avviene, consulta la guida alla Risoluzione dei problemi.

Cosa ottieni senza licenza

Una licenza mancante non genera eccezioni. Il viewer si rende normalmente, ma ogni pagina mostra una filigrana di valutazione. Vedi la Configurazione licenza per capire come Doconut trova una licenza e quali cambiamenti avvengono una volta trovata.

Questa pagina è stata utile?