Démarrage rapide

Rendez votre premier document en quelques minutes

Ce guide conduit une application ASP.NET Core d'un Program.cs vide à un document rendu dans le navigateur : enregistrement du serveur, le package complet du Viewer (barre d'outils du Viewer, montage du Viewer et rubans de Recherche/Annotation optionnels), les références d'actifs, l'initialisation du client, l'ouverture du document et l'exécution.

Configuration du serveur

AddDoconut() enregistre les services ; UseDoconutResources() et UseDoconut() connectent le middleware. L'appel aux ressources doit être effectué en premier. Les appels de session sont également requis — la sécurité de document par défaut de Doconut valide chaque requête de page contre l'état de session ASP.NET. Déjà enregistré Doconut lors de l'Installation ? Passez à la section suivante.

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();

Pour une configuration de chemins de style production, mappez le middleware de document vers une branche explicite et maintenez les quatre paramètres de chemin alignés :

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 est une valeur de coordination ; elle ne mappe pas une branche ASP.NET Core à elle seule. Dans cet exemple, l'hôte mappe /doconut, donc le client doit utiliser BasePath: '/doconut'. ResourcesPath sert le bundle intégré à /doconut-res, et le chemin des ressources d'images du widget est donc ResPath: '/doconut-res/images'.

Ajouter le visualiseur à une page

Le Viewer est le cœur requis de la page. Sa surface de rendu utilise deux div imbriqués :

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

Considérez la barre d'outils, les montages de modules et la surface du Viewer comme une composition unique de page. Recherche et Annotation injectent leurs rubans intégrés dans des montages optionnels, mais ces modules ne sont jamais autonomes : ils s'attachent toujours au Viewer sur la même page. Utilisez le même ordre que Doconut.TestApp et 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>

Référencer les ressources du visualiseur

Dans une vue Razor, le service Viewer injecté génère les balises <link> et <script> du visualiseur dans l'ordre de dépendance — le widget est un plugin jQuery, donc jQuery doit être chargé avant les scripts du visualiseur :

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
}))

Pour le package complet du Viewer, demandez les ressources du Viewer et des modules ensemble :

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 et IncludeViewerScripts sont les indicateurs de base obligatoires. Ne publiez jamais un exemple de ruban Recherche ou Annotation sans eux, le montage du Viewer, et une instance docViewer. ReferenceCss et ReferenceScripts omettent les ressources d'un module optionnel lorsque la licence actuelle ne le permet pas ; le Viewer de base démarre tout de même.

Initialiser le visualiseur

Le widget côté client est un plugin jQuery. Voici un ensemble minimal d'options d'initialisation réelles (pas du pseudocode) :

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);
    }
});

La casse des options est réellement mixte — showThumbs, autoLoad et pageZoom sont en camelCase, mais FitType, BasePath et ResPath sont en PascalCase. Il n'existe aucune règle cohérente ; une mauvaise casse entraîne l'ignorance silencieuse de l'option (le widget revient à sa valeur par défaut au lieu de lever une exception).

Assembler le package complet du Viewer

Les deux applications de référence .NET 6 installent les parties suivantes ensemble sur une même page :

Part of the packageRequirementHow it is connected
Viewer resources, mount, and objViewerRequiredCore document renderer
Viewer toolbarRequired in the reference compositionHost markup; buttons call the same objViewer
Search ribbonOptional, licensed moduledoconutSearchBar(...).attach(objViewer)
Annotation ribbonOptional, licensed moduledoconutAnnotationBar(...).attach(objViewer)

Bien que la barre d'outils principale du Viewer soit du balisage hôte, elle est installée avec le Viewer et ne doit jamais être documentée comme un contrôle isolé. Cela maintient sa mise en page, ses libellés, icônes et règles d'autorisation sous le contrôle de votre application tandis que chaque bouton pilote la même instance du 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 barre d'outils de référence complète copie également wwwroot/js/viewerToolbar.js dans l'application hôte pour les fonctions de rotation, vignette, impression, plein écran, mise en page et aides d'état des boutons. Chargez ce fichier hôte après Viewer.ReferenceScripts(...). Conservez l'aide et son balisage <nav id="toolbar"> ensemble lors de la copie de l'implémentation complète de la démo.

Conservez l'ordre d'initialisation du package utilisé par les deux applications de référence :

  1. Émettre le CSS pour le Viewer et les modules sous licence.
  2. Rendre la barre d'outils du Viewer, les montages Recherche/Annotation, et le montage du Viewer ensemble.
  3. Émettre les scripts pour le Viewer et les modules sous licence.
  4. Charger le viewerToolbar.js de l'application hôte.
  5. Initialiser docViewer et conserver le objViewer résultant.
  6. Initialiser chaque ruban Recherche ou Annotation sous licence.
  7. Appeler attach(objViewer) sur chaque ruban.
  8. Ouvrir le document et conserver son jeton pour les requêtes du Viewer et des modules.

Doconut.TestApp.Distributed conserve cette composition UI exacte et la même aide de barre d'outils du Viewer. Sa valeur de requête access supplémentaire et les paramètres de nouvelle tentative de rendu asynchrone appartiennent au transport distribué ; ils ne modifient pas la façon dont le Viewer, la barre d'outils ou les rubans sont assemblés.

Les garde-fous côté serveur sont importants : lorsqu'une capacité optionnelle n'est pas disponible, son script n'est pas émis, ainsi sa fonction de plugin jQuery n'existe pas.

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>

Les deux composants intégrés génèrent leur propre DOM de ruban. Recherche contient les groupes Trouver, Options et Résultats. Annotation contient ses outils d'édition, contrôles de style, actions d'enregistrement et actions d'exportation/image optionnelles. Les barres exposent open(), close(), reset() et isOpen() ; appelez toujours attach(objViewer) une fois après les avoir créées.

Exemple ci‑dessus omet les rappels hôte optionnels et les points de terminaison d'exportation/image d'Annotation afin de garder le démarrage minimal. Voir Recherche et Annotations pour la configuration complète spécifique aux fonctionnalités, ou Thèmes personnalisés pour styliser ou remplacer la barre d'outils du Viewer détenue par l'hôte.

Ouvrir un document

Le côté serveur se compose d'un seul point de terminaison : le service Viewer injecté ouvre le document et renvoie un jeton de session.

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 });
});

Le client récupère ce jeton et le transmet au widget avec objViewer.View(token) :

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

Fermer le document

Appelez objViewer.Close() lorsque l'utilisateur quitte le visualiseur ou ouvre un document de remplacement. Dans les flux de travail pilotés par le serveur, viewer.CloseDocument(token) supprime immédiatement la session en cache, libère le moteur de rendu, supprime son marqueur de sécurité et révoque le jeton. L'expiration glissante effectue finalement le même nettoyage, mais une fermeture explicite est recommandée pour les gros documents.

Le flux de requête complet est :

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

Traitez le jeton comme une preuve d'identité : ne le consignez jamais, ne le persistez jamais, ne le transmettez qu'au widget. Il identifie une session de document active sur le serveur et cesse de fonctionner lorsque cette session expire — rouvrez le document pour en obtenir un nouveau.

Exécuter

Placez un PDF dans wwwroot/files/Sample.pdf, exécutez dotnet run et ouvrez la page qui héberge le widget. La première page se rend dans le visualiseur, avec un panneau de vignettes à gauche. Si cela ne fonctionne pas, consultez Dépannage.

Ce que vous obtenez sans licence

Une licence manquante ne génère pas d'exception. Le visualiseur rend normalement, mais chaque page porte un filigrane d'évaluation. Voir Configuration de licence pour savoir comment Doconut trouve une licence et ce qui change une fois qu'elle est détectée.

Cette page vous a-t-elle été utile ?