Démarrage rapide

Rendez votre premier document opérationnel en quelques minutes

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

L’application hôte doit cibler un runtime qui prend en charge netstandard2.1 — .NET Core 3.0 ou version ultérieure. Les applications de référence livrées avec cette version ciblent net8.0.

Server setup

AddDoconut() enregistre les services ; UseDoconutResources() et UseDoconut() branchent le middleware. L’appel aux ressources doit être fait en premier. Les appels de session sont également requis — la sécurité des documents Doconut valide chaque requête de page contre l’état de session ASP.NET. L’état de session nécessite un cache : AddDistributedMemoryCache() en fournit un. Une application MVC ou Razor Pages l’enregistre déjà, mais une application minimal‑API ne le fait pas, et sans cela l’application s’arrête au démarrage avec Unable to resolve service for type 'IDistributedCache'. Déjà enregistré Doconut lors de Installation ? Passez à la section suivante.

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
});
builder.Services.AddDistributedMemoryCache(); // l'état de session nécessite un cache (MVC/Razor Pages en ajoutent déjà un)
builder.Services.AddSession(); // la sécurité des documents Doconut repose sur l'état de session ASP.NET

app.UseSession();          // appeler UseSession() avant UseDoconut()
app.UseDoconutResources(); // doit être enregistré avant UseDoconut()
app.UseDoconut();

L’application de référence conserve la forme historique de la requête DocImage.axd et monte le middleware de document sur une branche correspondante. C’est l’arrangement à copier lorsque vous faites évoluer une application .NET Standard existante, car le client continue d’appeler la même URL qu’il a toujours utilisée :

csharp
builder.Services.AddDoconut(options =>
{
    options.UnsafeMode      = false;   // conserver la vérification de session de Doconut activée
    options.ShowDoconutInfo = false;
});
builder.Services.AddDistributedMemoryCache(); // l'état de session nécessite un cache (MVC/Razor Pages en ajoutent déjà un)
builder.Services.AddSession(options =>
{
    options.IdleTimeout        = TimeSpan.FromSeconds(3600);
    options.Cookie.HttpOnly    = true;
    options.Cookie.IsEssential = true;
});

// Nécessaire pour les encodages multi-octets dans certains formats de document.
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

app.UseStaticFiles();
app.UseRouting();
app.UseSession();
app.UseDoconutResources();   // AVANT la branche de document
app.MapWhen(
    context => context.Request.Path.Value?.EndsWith("DocImage.axd", StringComparison.OrdinalIgnoreCase) == true,
    branch => branch.UseDoconut());

UseDoconut() ne prend aucune option dans cette version — tout a été déplacé vers AddDoconut(). MiddlewarePath est une valeur de coordination ; elle ne mappe pas une branche ASP.NET Core à elle seule. ResourcesPath sert le bundle intégré à /doconut-res, et le chemin des ressources d’image du widget est donc ResPath: 'doconut-res/images'.

Add the viewer to a 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. La Recherche et l’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.

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é émet 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 visualiseur, demandez les ressources du visualiseur 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 de recherche ou d'annotation sans eux, le montage du visualiseur et une instance docViewer. ReferenceCss et ReferenceScripts omettent les ressources d'un module optionnel lorsque la licence actuelle ne permet pas cette capacité ; le visualiseur de base démarre quand même.

Ces appels remplacent les fichiers de script copiés à la main. Si l'application charge encore ses propres docViewer.js, documentLinks.js ou docViewer.UI.js, supprimez ces balises une fois que la page fonctionne avec les ressources émises — voir le guide de migration.

Initialiser le visualiseur

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

javascript
let searchBar = null;
let annBar = null;

const objViewer = $('#div_ctlDoc').docViewer({
    showThumbs: true,
    autoLoad:   false,
    pageZoom:   100,
    FitType:    'width',
    BasePath:   '/',
    ResPath:    'doconut-res/images',
    onViewerReady: function () {
        // les pages sont visibles ; il est sûr de masquer un indicateur de chargement ici
    },
    // Transmettre les événements du cycle de vie des annotations au ruban intégré lorsqu'il est présent.
    onAnnLoaded:    () => annBar?.handleAnnLoaded(),
    onAnnSaved:     () => annBar?.handleAnnSaved(),
    onAnnSaveError: () => annBar?.handleAnnSaveError(),
    onAnnClosed:    () => annBar?.handleAnnClosed(),
    onError: function (message) {
        console.error('Doconut viewer error:', message);
    }
});

Deux détails décident si cette page fonctionne du tout :

  • Les rappels sont des options. onViewerReady, onViewerBusy, onCopy et onAutoLoadStatus sont passés dans l'objet d'options. Le visualiseur précédent dérivait les noms de fonctions globales à partir de l'ID du conteneur et les appelait ; celui‑ci ne le fait pas. Un gestionnaire déclaré uniquement comme fonction globale ne s'exécute jamais, et rien n'est signalé.
  • ResPath pointe vers le préfixe des ressources, pas la racine de l'application. Avec le ResourcesPath par défaut, cette valeur est doconut-res/images. Si vous avez modifié ResourcesPath, utilisez votre propre préfixe à la place.

Les deux échouent silencieusement — voir la section Dépannage et le guide de migration.

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 visualiseur

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

Partie du packageExigenceComment elle est connectée
Ressources du visualiseur, montage et objViewerObligatoireMoteur de rendu de document de base
Barre d'outils du visualiseurObligatoire dans la composition de référenceBalise hôte ; les boutons appellent le même objViewer
Ruban de rechercheOptionnel, module sous licencedoconutSearchBar(...).attach(objViewer)
Ruban d'annotationOptionnel, module sous licencedoconutAnnotationBar(...).attach(objViewer)

Bien que la barre d'outils principale du visualiseur soit du balisage hôte, elle est installée à côté du visualiseur et ne doit jamais être documentée comme un contrôle isolé. Cela maintient sa mise en page, ses libellés, ses icônes et ses règles d'autorisation sous le contrôle de votre application tandis que chaque bouton pilote la même instance du visualiseur :

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>

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

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

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. La recherche contient les groupes Trouver, Options et Résultats. L'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.

Le 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 visualiseur détenue par l'hôte.

Ouvrir un document

Le côté serveur ne comporte qu’un point de terminaison : le service Viewer injecté ouvre le document et renvoie un jeton de session. L’ouverture est asynchrone dans cette version.

csharp
app.MapPost("/api/open", async (Viewer viewer) =>
{
    // Le jeton est opaque — transmettez‑le au widget, ne le consignez ni ne le persistez jamais.
    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);
    });

Il n’y a rien à préchauffer avant la première ouverture. Si vous faites évoluer une application, supprimez tout appel à InitCache() ainsi que le drapeau qui le protège — la méthode n’existe plus.

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 mise en cache, libère le moteur de rendu, efface 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 documents volumineux.

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 un credential porteur : ne le consignez jamais, ne le persistez jamais, transmettez‑le uniquement au widget. Il identifie une session de document active sur le serveur et cesse de fonctionner lorsque cette session expire — ré‑ouvrez le document pour en obtenir un nouveau.

Exécuter

Placez un PDF dans wwwroot/files/Sample.pdf, lancez dotnet run et ouvrez la page qui héberge le widget. La première page s’affiche dans le visualiseur, avec un panneau de vignettes à gauche. Si cela ne se produit 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. Consultez Configuration de licence pour savoir comment Doconut trouve une licence et quels changements interviennent une fois qu’elle est détectée.

Cette page était-elle utile ?