Schnellstart

Rendern Sie Ihr erstes Dokument in wenigen Minuten

Dieses Tutorial führt eine ASP.NET Core‑App von einer leeren Program.cs zu einem im Browser gerenderten Dokument: Serverregistrierung, das komplette Viewer‑Paket (Viewer‑Symbolleiste, Viewer‑Einbindung und optionale Such‑/Anmerkungs‑Ribbons), Asset‑Referenzen, Client‑Initialisierung, Dokumentöffnung und Ausführung.

Die Host‑Anwendung muss ein Laufzeit‑Target unterstützen, das netstandard2.1 unterstützt — .NET Core 3.0 oder höher. Die mit dieser Veröffentlichung ausgelieferten Referenzanwendungen zielen auf net8.0.

Servereinrichtung

AddDoconut() registriert die Services; UseDoconutResources() und UseDoconut() verbinden die Middleware. Der Aufruf der Ressourcen muss zuerst erfolgen. Die Sitzungsaufrufe sind ebenfalls erforderlich — die standardmäßige Dokumentensicherheit von Doconut prüft jede Seitenanforderung gegen den ASP.NET‑Sitzungszustand. Der Sitzungszustand benötigt einen Cache: AddDistributedMemoryCache() stellt einen bereit. Eine MVC‑ oder Razor‑Pages‑App registriert ihn bereits, aber eine Minimal‑API‑App tut dies nicht; ohne ihn bricht die Anwendung beim Start mit Unable to resolve service for type 'IDistributedCache' ab. Haben Sie Doconut bereits während der Installation registriert? Springen Sie zum nächsten Abschnitt.

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
});
builder.Services.AddDistributedMemoryCache(); // Der Sitzungszustand benötigt einen Cache (MVC/Razor Pages fügen bereits einen hinzu)
builder.Services.AddSession(); // Die Doconut‑Dokumentsicherheit basiert auf dem ASP.NET‑Sitzungszustand

app.UseSession();          // Rufen Sie UseSession() vor UseDoconut() auf
app.UseDoconutResources(); // muss vor UseDoconut() registriert werden
app.UseDoconut();

Die Referenzanwendung behält die historische DocImage.axd‑Anfrageform bei und bindet die Dokument‑Middleware an einem passenden Zweig ein. Dies ist die zu kopierende Anordnung, wenn Sie eine bestehende .NET‑Standard‑Anwendung weiterführen, da der Client weiterhin dieselbe URL aufruft, die er immer verwendet hat:

csharp
builder.Services.AddDoconut(options =>
{
    options.UnsafeMode      = false;   // Doconut‑Sitzungsprüfung aktiviert lassen
    options.ShowDoconutInfo = false;
});
builder.Services.AddDistributedMemoryCache(); // Der Sitzungszustand benötigt einen Cache (MVC/Razor Pages fügen bereits einen hinzu)
builder.Services.AddSession(options =>
{
    options.IdleTimeout        = TimeSpan.FromSeconds(3600);
    options.Cookie.HttpOnly    = true;
    options.Cookie.IsEssential = true;
});

// Erforderlich für Mehrbyte‑Kodierungen in einigen Dokumentformaten.
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

app.UseStaticFiles();
app.UseRouting();
app.UseSession();
app.UseDoconutResources();   // VOR dem Dokumentzweig
app.MapWhen(
    context => context.Request.Path.Value?.EndsWith("DocImage.axd", StringComparison.OrdinalIgnoreCase) == true,
    branch => branch.UseDoconut());

UseDoconut() nimmt in dieser Veröffentlichung keine Optionen entgegen — alles wurde zu AddDoconut() verschoben. MiddlewarePath ist ein Koordinationswert; er mappt keinen ASP.NET Core‑Zweig von sich aus. ResourcesPath stellt das eingebettete Bundle unter /doconut-res bereit, und der Bild‑Ressourcen‑Pfad des Widgets lautet daher ResPath: 'doconut-res/images'.

Viewer zur Seite hinzufügen

Der Viewer ist der erforderliche Kern der Seite. Seine Rendering‑Oberfläche verwendet zwei verschachtelte divs:

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

Betrachten Sie die Symbolleiste, Modul‑Einbindungen und die Viewer‑Oberfläche als eine Seitenkomposition. Suche und Anmerkung fügen ihre eingebetteten Ribbons in optionale Einbindungen ein, aber diese Module stehen niemals eigenständig: Sie werden immer am Viewer auf derselben Seite angehängt.

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>

Referenzieren der Viewer‑Assets

In einer Razor‑View gibt der injizierte Viewer‑Dienst die <link>‑ und <script>‑Tags des Viewers in Abhängigkeitsreihenfolge aus — das Widget ist ein jQuery‑Plugin, daher muss jQuery vor den Viewer‑Skripten geladen werden:

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

Für das vollständige Viewer‑Paket werden die Viewer‑ und Modul‑Ressourcen gemeinsam angefordert:

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 und IncludeViewerScripts sind die obligatorischen Kern‑Flags. Veröffentlichen Sie niemals ein Beispiel für das Such‑ oder Anmerkungs‑Ribbon ohne diese, die Viewer‑Einbindung und eine docViewer‑Instanz. ReferenceCss und ReferenceScripts lassen die Ressourcen eines optionalen Moduls weg, wenn die aktuelle Lizenz diese Fähigkeit nicht gewährt; der Kern‑Viewer startet trotzdem.

Diese Aufrufe ersetzen handkopierte Skriptdateien. Wenn die Anwendung noch ihre eigenen docViewer.js, documentLinks.js oder docViewer.UI.js lädt, entfernen Sie diese Tags, sobald die Seite mit den ausgegebenen Ressourcen funktioniert — siehe den Migrationsleitfaden.

Viewer initialisieren

Das clientseitige Widget ist ein jQuery‑Plugin. Dies ist ein minimales Set echter Initialisierungsoptionen (kein 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 () {
        // Seiten sind sichtbar; ein Lade‑Spinner kann hier sicher ausgeblendet werden
    },
    // Weiterleiten von Anmerkungs‑Lebenszyklusereignissen an das eingebettete Ribbon, wenn es vorhanden ist.
    onAnnLoaded:    () => annBar?.handleAnnLoaded(),
    onAnnSaved:     () => annBar?.handleAnnSaved(),
    onAnnSaveError: () => annBar?.handleAnnSaveError(),
    onAnnClosed:    () => annBar?.handleAnnClosed(),
    onError: function (message) {
        console.error('Doconut viewer error:', message);
    }
});

Zwei Details entscheiden, ob diese Seite überhaupt funktioniert:

  • Callbacks sind Optionen. onViewerReady, onViewerBusy, onCopy und onAutoLoadStatus werden im Options‑Objekt übergeben. Der vorherige Viewer leitet globale Funktionsnamen aus der Container‑ID ab und rief sie auf; dieser tut das nicht. Ein Handler, der nur als globale Funktion deklariert ist, wird nie ausgeführt, und es wird nichts gemeldet.
  • ResPath zeigt auf das Ressourcen‑Präfix, nicht auf das Anwendungs‑Root. Beim Standard‑ResourcesPath ist dieser Wert doconut-res/images. Wenn Sie ResourcesPath geändert haben, verwenden Sie stattdessen Ihr eigenes Präfix.

Beide Fehler werden stillschweigend ignoriert — siehe Fehlerbehebung und den Migrationsleitfaden.

Die Schreibweise der Optionen ist tatsächlich gemischt — showThumbs, autoLoad und pageZoom sind camelCase, aber FitType, BasePath und ResPath sind PascalCase. Es gibt keine konsistente Regel; falsche Schreibweise führt dazu, dass die Option stillschweigend ignoriert wird (das Widget fällt auf seine Vorgabe zurück, anstatt einen Fehler zu werfen).

Zusammensetzen des vollständigen Viewer‑Pakets

Beide Referenz‑Applikationen installieren die folgenden Teile zusammen auf einer Seite:

Teil des PaketsAnforderungWie es verbunden ist
Viewer‑Ressourcen, Einbindung und objViewerErforderlichKern‑Dokumentrenderer
Viewer‑WerkzeugleisteIm Referenzaufbau erforderlichHost‑Markup; Buttons rufen dasselbe objViewer auf
Such‑RibbonOptionales, lizenziertes ModuldoconutSearchBar(...).attach(objViewer)
Anmerkungs‑RibbonOptionales, lizenziertes ModuldoconutAnnotationBar(...).attach(objViewer)

Obwohl die Haupt‑Viewer‑Werkzeugleiste Host‑Markup ist, wird sie zusammen mit dem Viewer installiert und darf niemals als isoliertes Steuerelement dokumentiert werden. So bleiben Layout, Beschriftungen, Icons und Autorisierungsregeln unter Ihrer Anwendungs‑Kontrolle, während jeder Button dieselbe Viewer‑Instanz steuert:

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>

Behalten Sie die Initialisierungsreihenfolge des Pakets bei, die von beiden Referenz‑Applikationen verwendet wird:

  1. CSS für den Viewer und lizenzierte Module ausgeben.
  2. Viewer‑Werkzeugleiste, Such‑/Anmerkungs‑Einbindungen und Viewer‑Einbindung zusammen rendern.
  3. Skripte für den Viewer und lizenzierte Module ausgeben.
  4. Hilfsskript für die Werkzeugleiste der Host‑Anwendung laden.
  5. docViewer initialisieren und das resultierende objViewer behalten.
  6. Jedes lizenzierte Such‑ oder Anmerkungs‑Ribbon initialisieren.
  7. attach(objViewer) für jedes Ribbon aufrufen.
  8. Dokument öffnen und dessen Token für Viewer‑ und Modul‑Anfragen behalten.

Die serverseitigen Guard‑Mechanismen sind wichtig: Wenn eine optionale Fähigkeit nicht verfügbar ist, wird ihr Skript nicht ausgegeben, sodass die jQuery‑Plug‑in‑Funktion nicht existiert.

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>

Beide eingebetteten Komponenten erzeugen ihr eigenes Ribbon‑DOM. Die Suche enthält Gruppen „Find“, „Options“ und „Results“. Die Anmerkungen enthalten ihre Autorentools, Stil‑Steuerungen, Speicher‑Aktionen und optionale Export‑/Bild‑Aktionen. Die Bars stellen open(), close(), reset() und isOpen() bereit; rufen Sie stets einmal nach deren Erstellung attach(objViewer) auf.

Das obige Beispiel lässt optionale Host‑Callbacks und Anmerkungs‑Export‑/Bild‑Endpunkte weg, um den Start minimal zu halten. Siehe Suche und Anmerkungen für die vollständige, funktionsspezifische Einrichtung oder Benutzerdefinierte Designs, um die vom Host besessene Viewer‑Werkzeugleiste zu stylen oder zu ersetzen.

Dokument öffnen

Die Serverseite besteht aus einem Endpunkt: Der injizierte Viewer‑Dienst öffnet das Dokument und gibt ein Session‑Token zurück. Das Öffnen ist in dieser Version asynchron.

csharp
app.MapPost("/api/open", async (Viewer viewer) =>
{
    // Das Token ist undurchsichtig — übergeben Sie es dem Widget, protokollieren oder speichern Sie es niemals.
    string token = await viewer.OpenDocumentAsync("wwwroot/files/Sample.pdf");
    return Results.Ok(new { token });
});

Der Client holt dieses Token und übergibt es dem Widget mit objViewer.View(token):

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

Es gibt nichts aufzuwärmen, bevor das erste Öffnen erfolgt. Wenn Sie eine Anwendung weiterführen, entfernen Sie jeden Aufruf von InitCache() und das dazugehörige Flag – die Methode existiert nicht mehr.

Dokument schließen

Rufen Sie objViewer.Close() auf, wenn der Benutzer den Viewer verlässt oder ein Ersatzdokument öffnet. Bei servergesteuerten Workflows entfernt viewer.CloseDocument(token) sofort die zwischengespeicherte Sitzung, gibt die Rendering‑Engine frei, löscht dessen Sicherheitsmarker und widerruft das Token. Ein gleitendes Ablaufdatum führt schließlich dieselbe Bereinigung durch, aber ein explizites Schließen wird für große Dokumente empfohlen.

Der abgeschlossene Anforderungsablauf ist:

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

Behandeln Sie das Token wie ein Bearer‑Credential: Protokollieren Sie es niemals, speichern Sie es nicht, geben Sie es nur an das Widget weiter. Es identifiziert eine aktive Dokumentsitzung auf dem Server und hört auf zu funktionieren, wenn diese Sitzung abläuft – öffnen Sie das Dokument erneut, um ein frisches Token zu erhalten.

Ausführen

Legen Sie ein PDF unter wwwroot/files/Sample.pdf ab, führen Sie dotnet run aus und öffnen Sie die Seite, die das Widget hostet. Die erste Seite wird im Viewer gerendert, mit einer Miniatur‑Leiste links. Wenn dies nicht geschieht, siehe Fehlerbehebung.

Was Sie ohne Lizenz erhalten

Eine fehlende Lizenz löst keinen Fehler aus. Der Viewer rendert normal, aber jede Seite trägt ein Evaluations‑Wasserzeichen. Siehe Lizenzsetup für Informationen, wie Doconut eine Lizenz findet und welche Änderungen danach auftreten.

War diese Seite hilfreich?