Schnellstart
Rendern Sie Ihr erstes Dokument in Minuten
Dieses Tutorial 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‑Werkzeugleiste, Viewer‑Mount und optionale Such‑/Annotations‑Ribbons), Asset‑Referenzen, Client‑Initialisierung, Dokument‑Öffnung und Ausführung.
Servereinrichtung
AddDoconut() registriert die Services; UseDoconutResources() und UseDoconut() verbinden die Middleware. Der Aufruf der Ressourcen muss zuerst erfolgen. Die Session‑Aufrufe sind ebenfalls erforderlich — Doconut's standardmäßige Dokumentensicherheit validiert jede Seitenanforderung gegen den ASP.NET‑Session‑State. Bereits Doconut während der Installation registriert? 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 ordnen Sie die Dokument‑Middleware einem expliziten Branch zu und halten die vier Pfadeinstellungen synchron:
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 selbst. 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 zur Seite hinzufügen
Der Viewer ist der erforderliche Kern der Seite. Seine Rendering‑Oberfläche verwendet zwei verschachtelte divs:
<div id="divDocViewer">
<div id="div_ctlDoc"></div>
</div>Behandeln Sie die Werkzeugleiste, Modul‑Mounts und die Viewer‑Oberfläche als eine Seiten‑Komposition. Suche und Annotation fügen ihre eingebetteten Ribbons in optionale Mounts ein, aber diese Module stehen niemals eigenständig: Sie werden immer an den Viewer auf derselben Seite angehängt. Verwenden Sie dieselbe Reihenfolge wie 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>Referenzieren der Viewer‑Assets
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 Such‑ oder Annotations‑Ribbon‑Beispiel ohne sie, 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 dennoch.
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, aber FitType, BasePath und ResPath sind PascalCase. Es gibt keine konsistente Regel; wird die Schreibweise falsch verwendet, wird die Option stillschweigend ignoriert (das Widget fällt auf seine Vorgabe zurück, anstatt einen Fehler zu werfen).
Komplettes Viewer‑Paket zusammenstellen
Beide .NET 8‑Referenzanwendungen installieren die folgenden Teile zusammen auf einer Seite:
| Teil des Pakets | Anforderung | Wie es verbunden ist |
|---|---|---|
Viewer‑Ressourcen, Mount und objViewer | Erforderlich | Kern‑Dokument‑Renderer |
| Viewer‑Werkzeugleiste | Erforderlich in der Referenz‑Zusammensetzung | Host‑Markup; Buttons rufen das gleiche objViewer auf |
| Such‑Ribbon | Optional, lizenziertes Modul | doconutSearchBar(...).attach(objViewer) |
| Annotations‑Ribbon | Optional, lizenziertes Modul | doconutAnnotationBar(...).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:
<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‑Werkzeugleiste 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 vollständige Demo‑Implementierung kopieren.
Behalten Sie die Initialisierungsreihenfolge des Pakets bei, die von beiden Referenzanwendungen verwendet wird:
- Emitieren Sie Viewer-, Such- und Annotations‑Ressourcen zusammen.
- Rendern Sie die Viewer‑Werkzeugleiste, Ribbon‑Mounts und den Viewer‑Mount zusammen.
- Initialisieren Sie
docViewerzuerst. - Erstellen Sie jedes lizenzierte Ribbon und hängen Sie es an dasselbe
objVieweran. - Öffnen Sie das Dokument und behalten Sie sein Token für Modul‑Anfragen.
Doconut.TestApp.Distributed behält genau diese UI‑Zusammensetzung und denselben Viewer‑Toolbar‑Helper bei. Sein zusätzlicher access‑Request‑Wert und die asynchronen Render‑Retry‑Einstellungen gehören zum verteilten Transport; sie ändern nicht, wie Viewer, Werkzeugleiste oder Ribbons zusammengebaut werden.
Die serverseitigen Schutzmechanismen sind wichtig: Wenn eine optionale Fähigkeit nicht verfügbar ist, 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. Suche enthält Gruppen „Find“, „Options“ und „Results“. Annotation enthält seine Autorentools, Stil‑Steuerungen, Speicher‑Aktionen und optionale Export‑/Bild‑Aktionen. Die Bars stellen open(), close(), reset() und isOpen() bereit; rufen Sie stets nach der Erstellung einmal 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 und Annotationen für die vollständige funktionsspezifische Einrichtung oder Benutzerdefinierte Themen, um die host‑eigene Viewer‑Werkzeugleiste zu stylen oder zu ersetzen.
Dokument öffnen
Die Serverseite besteht aus einem 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 Ersatzdokument öffnet. Bei servergesteuerten Workflows entfernt viewer.CloseDocument(token) sofort die zwischengespeicherte Session, gibt die Rendering‑Engine frei, löscht das Sicherheits‑Marker und widerruft das Token. Das gleitende Ablaufdatum führt später dieselbe Bereinigung durch, aber ein explizites Schließen wird für große Dokumente empfohlen.
Der abgeschlossene Anforderungsablauf ist:
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: Loggen Sie es nie, persistieren Sie es nie, geben Sie es nur an das Widget weiter. Es identifiziert eine aktive Dokumentsession auf dem Server und hört auf zu funktionieren, wenn 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 gerendert, mit einer Thumbnail‑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 eintreten.
War diese Seite hilfreich?