Schnellstart
Rendern Sie Ihr erstes Dokument in Minuten
Dieser Leitfaden führt eine ASP.NET Core‑App von einer leeren Program.cs zu einem im Browser gerenderten Dokument: Server‑Registrierung, das komplette Viewer‑Paket (Viewer‑Toolbar, Viewer‑Mount und optionale Such‑/Annotations‑Bänder), Asset‑Referenzen, Client‑Initialisierung, Dokument‑Öffnung und Ausführung.
Server‑Einrichtung
AddDoconut() registriert die Services; UseDoconutResources() und UseDoconut() binden die Middleware ein. Der Aufruf der Ressourcen muss zuerst erfolgen. Die Session‑Aufrufe sind ebenfalls erforderlich — Doconut‑Standard‑Dokumentensicherheit validiert jede Seitenanforderung gegen den ASP.NET‑Session‑State. Haben Sie Doconut bereits während der Installation registriert? Dann springen Sie zum nächsten Abschnitt.
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();Für ein produktionsähnliches Pfad‑Layout, binden Sie die Dokument‑Middleware an einen expliziten Branch und halten Sie die vier Pfad‑Einstellungen abgestimmt:
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 ist ein Koordinationswert; er mappt keinen ASP.NET Core‑Branch von allein. In diesem Beispiel mappt der Host /doconut, sodass der Client BasePath: '/doconut' verwenden muss. ResourcesPath stellt das eingebettete Bundle unter /doconut-res bereit, und der Bild‑Ressourcen‑Pfad des Widgets lautet daher ResPath: '/doconut-res/images'.
Viewer zu einer Seite hinzufügen
Der Viewer ist das erforderliche Kern‑Element der Seite. Seine Rendering‑Oberfläche verwendet zwei verschachtelte divs:
<div id="divDocViewer">
<div id="div_ctlDoc"></div>
</div>Behandeln Sie die Toolbar, Modul‑Mounts und die Viewer‑Oberfläche als eine Seiten‑Komposition. Suche und Annotation fügen ihre eingebetteten Bänder in optionale Mounts ein, aber diese Module stehen nie allein: Sie hängen immer am Viewer derselben Seite. Verwenden Sie dieselbe Reihenfolge wie in Doconut.TestApp und Doconut.TestApp.Distributed:
<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>Viewer‑Assets referenzieren
In einer Razor‑View gibt der injizierte Viewer‑Service 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:
@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 komplette Viewer‑Paket fordern Sie Viewer‑ und Modul‑Ressourcen gemeinsam an:
@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 ein Such‑ oder Annotations‑Band, ohne diese, den Viewer‑Mount 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.
Viewer initialisieren
Das clientseitige Widget ist ein jQuery‑Plugin. Dies ist ein minimales Set echter Initialisierungs‑Optionen (kein Pseudocode):
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);
}
});Die Schreibweise der Optionen ist tatsächlich gemischt — showThumbs, autoLoad und pageZoom sind camelCase, FitType, BasePath und ResPath PascalCase. Es gibt keine konsistente Regel; wird die Schreibweise falsch verwendet, wird die Option stillschweigend ignoriert (das Widget fällt auf seine Standardwerte zurück, anstatt einen Fehler zu werfen).
Komplettes Viewer‑Paket zusammenstellen
Beide .NET 6‑Referenzanwendungen installieren die folgenden Teile gemeinsam auf einer Seite:
| Teil des Pakets | Anforderung | Wie es verbunden ist |
|---|---|---|
Viewer‑Ressourcen, Mount und objViewer | Erforderlich | Kern‑Dokument‑Renderer |
| Viewer‑Toolbar | Erforderlich in der Referenz‑Komposition | Host‑Markup; Buttons rufen dasselbe objViewer auf |
| Such‑Band | Optional, lizenziertes Modul | doconutSearchBar(...).attach(objViewer) |
| Annotations‑Band | Optional, lizenziertes Modul | doconutAnnotationBar(...).attach(objViewer) |
Obwohl die Haupt‑Viewer‑Toolbar 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 Kontrolle Ihrer Anwendung, während jeder Button dieselbe Viewer‑Instanz steuert:
<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>Die vollständige Referenz‑Toolbar kopiert außerdem wwwroot/js/viewerToolbar.js in die Host‑Anwendung für Dreh‑, Thumbnail‑, Druck‑, Vollbild‑, Layout‑ und Button‑State‑Hilfen. Laden Sie diese Host‑Datei nach Viewer.ReferenceScripts(...). Halten Sie den Helfer und sein <nav id="toolbar">‑Markup zusammen, wenn Sie die komplette Demo‑Implementierung kopieren.
Behalten Sie die Initialisierungs‑Reihenfolge bei, die von beiden Referenz‑Anwendungen verwendet wird:
- CSS für den Viewer und lizenzierte Module ausgeben.
- Viewer‑Toolbar, Such‑/Annotations‑Mounts und Viewer‑Mount gemeinsam rendern.
- Skripte für den Viewer und lizenzierte Module ausgeben.
- Die Host‑Datei
viewerToolbar.jsladen. docViewerinitialisieren und das resultierendeobjViewerbehalten.- Jedes lizenzierte Such‑ oder Annotations‑Band initialisieren.
attach(objViewer)für jedes Band aufrufen.- Das Dokument öffnen und sein Token für Viewer‑ und Modul‑Anfragen behalten.
Doconut.TestApp.Distributed behält exakt diese UI‑Komposition und denselben Viewer‑Toolbar‑Helfer bei. Sein zusätzlicher access‑Request‑Wert und die asynchronen Render‑Retry‑Einstellungen gehören zum verteilten Transport; sie ändern nicht, wie Viewer, Toolbar oder Bänder zusammengesetzt werden.
Die serverseitigen Guard‑Mechanismen sind wichtig: Ist eine optionale Fähigkeit nicht verfügbar, wird ihr Skript nicht ausgegeben, sodass die jQuery‑Plug‑in‑Funktion nicht existiert.
<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 für Finden, Optionen und Ergebnisse. Die Annotation enthält ihre Autorentools, Stil‑Steuerungen, Speicher‑Aktionen und optionale Export‑/Bild‑Aktionen. Die Bänder 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 Annotation‑Export‑/Bild‑Endpunkte weg, um den Start minimal zu halten. Siehe Suche (../guides/search) und Annotationen (../guides/annotations) für die vollständige, funktionsspezifische Einrichtung oder Benutzerdefinierte Themen (../guides/custom-themes), um die host‑eigene Viewer‑Toolbar zu stylen oder zu ersetzen.
Dokument öffnen
Serverseitig gibt es einen Endpunkt: Der injizierte Viewer‑Service öffnet das Dokument und gibt ein Session‑Token zurück.
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 });
});Der Client holt dieses Token und übergibt es dem Widget mit objViewer.View(token):
fetch('/api/open', { method: 'POST' })
.then(resp => resp.json())
.then(data => {
currentToken = data.token;
objViewer.View(currentToken);
});Dokument schließen
Rufen Sie objViewer.Close() auf, wenn der Benutzer den Viewer verlässt oder ein Ersatz‑Dokument öffnet. In servergesteuerten Workflows entfernt viewer.CloseDocument(token) sofort die zwischengespeicherte Session, entsorgt die Rendering‑Engine, löscht das Sicherheits‑Marker und widerruft das Token. Das Sliding‑Expiration‑Verfahren führt dieselbe Bereinigung später aus, aber ein explizites Schließen wird für große Dokumente empfohlen.
Der vollständige Anforderungs‑Ablauf lautet:
AddDoconut + middleware
-> render CSS/scripts and mount div
-> initialize docViewer
-> OpenDocumentAsync
-> return opaque token
-> objViewer.View(token)
-> page/search/annotation requests
-> Close / CloseDocumentBehandeln Sie das Token wie ein Bearer‑Credential: Nie protokollieren, nie persistieren, nur dem Widget übergeben. Es identifiziert eine aktive Dokumentsession auf dem Server und wird ungültig, sobald diese Session abläuft — öffnen Sie das Dokument erneut, um ein frisches Token zu erhalten.
Ausführen
Legen Sie eine PDF‑Datei 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 angezeigt, mit einem Thumbnail‑Panel links. Sollte dies nicht geschehen, siehe Fehlerbehebung (../troubleshooting).
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 (license-setup) für Informationen, wie Doconut eine Lizenz findet und welche Änderungen danach wirksam werden.
War diese Seite hilfreich?