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‑Symbolleiste, Viewer‑Einbindung und optionale Such‑/Annotations‑Bänder), Asset‑Referenzen, Client‑Initialisierung, Dokumentöffnung und Ausführung.
Servereinrichtung
AddDoconut() registriert die Dienste; UseDoconutResources() und UseDoconut() verbinden die Middleware. Der Aufruf der Ressourcen muss zuerst erfolgen. Die Sitzungsaufrufe sind ebenfalls erforderlich — Doconut‑s Standard‑Dokumentensicherheit prüft jede Seitenanfrage 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, und ohne ihn stoppt die Anwendung beim Start mit Unable to resolve service for type 'IDistributedCache'. Haben Sie Doconut bereits während der Installation registriert? Springen Sie zum nächsten Abschnitt.
builder.Services.AddDoconut(options =>
{
options.LicensePath = "Doconut.Viewer.lic";
});
builder.Services.AddDistributedMemoryCache(); // Sitzungszustand benötigt einen Cache (MVC/Razor Pages fügt bereits einen hinzu)
builder.Services.AddSession(); // Doconut-Dokumentensicherheit nutzt den ASP.NET‑Sitzungszustand
app.UseSession(); // Aufruf von UseSession() vor UseDoconut()
app.UseDoconutResources(); // muss vor UseDoconut() registriert werden
app.UseDoconut();Für ein produktionsähnliches Pfadlayout 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, "wwwroot", "Doconut.Viewer.lic");
options.MiddlewarePath = "/doconut";
options.ResourcesPath = "/doconut-res";
options.UnsafeMode = false;
});
builder.Services.AddDistributedMemoryCache();
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 sich aus. In diesem Beispiel mappt der Host /doconut, sodass der Client BasePath: 'doconut' verwendet. ResourcesPath stellt das eingebettete Bundle unter /doconut-res bereit, und der Bild‑Ressourcen‑Pfad des Widgets lautet daher ResPath: 'doconut-res/images'. Schreiben Sie beide ohne führenden Schrägstrich: Der Viewer fügt selbst einen hinzu, sodass '/doconut' zu //doconut/DocImage.axd werden würde, was der Browser als Anfrage an einen Host namens doconut interpretiert und der Viewer mit „The viewer handler could not be reached“ fehlschlägt.
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>Betrachten Sie die Symbolleiste, Modul‑Einbindungen und die Viewer‑Oberfläche als eine Seitenkomposition. Suche und Annotation fügen ihre eingebetteten Bänder in optionale Einbindungen ein, aber diese Module stehen niemals eigenständig: Sie werden immer an den Viewer auf derselben Seite angehängt. Verwenden Sie die gleiche Reihenfolge wie bei Doconut.TestApp und Doconut.TestApp.Distributed:
<nav id="toolbar" aria-label="Document viewer controls">
<!-- Viewer‑Navigation, Zoom, Such‑ und Annotations‑Schaltflächen -->
</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‑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:
@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‑Band‑Beispiel 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 dennoch.
Viewer initialisieren
Das clientseitige Widget ist ein jQuery‑Plugin. Dies ist ein minimales Set echter Initialisierungsoptionen (kein Pseudocode):
let searchBar = null;
let annBar = null;
const objViewer = $('#div_ctlDoc').docViewer({
showThumbs: true,
autoLoad: false,
pageZoom: 100,
FitType: 'width',
BasePath: 'doconut', // kein führender '/'
ResPath: 'doconut-res/images', // kein führender '/'
onViewerReady: function () {
// Seiten sind sichtbar; ein Lade‑Spinner kann hier sicher ausgeblendet werden
},
// Leite Annotations‑Lebenszyklus‑Ereignisse an das eingebettete Ribbon weiter, 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);
}
});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 greift auf seine Standardeinstellung zurück, anstatt einen Fehler zu werfen).
Komplettes Viewer‑Paket zusammenstellen
Beide .NET 6‑Referenzanwendungen installieren die folgenden Teile zusammen auf einer Seite:
| Teil des Pakets | Anforderung | Wie es verbunden ist |
|---|---|---|
Viewer‑Ressourcen, Einbindung und objViewer | Erforderlich | Kern‑Dokument‑Renderer |
| Viewer‑Werkzeugleiste | Erforderlich in der Referenzzusammensetzung | Host‑Markup; Buttons rufen denselben objViewer auf |
| Such‑Ribbon | Optionales, lizenziertes Modul | doconutSearchBar(...).attach(objViewer) |
| Annotations‑Ribbon | Optionales, 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 der 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 Drehung, Miniaturansichten, Druck, Vollbild, Layout und Hilfsfunktionen für den Button‑Zustand. 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 Initialisierungsreihenfolge des Pakets bei, die von beiden Referenzanwendungen verwendet wird:
- CSS für den Viewer und lizensierte Module ausgeben.
- Viewer‑Werkzeugleiste, Such‑/Annotations‑Einbindungen und Viewer‑Einbindung zusammen rendern.
- Skripte für den Viewer und lizensierte Module ausgeben.
- Die
viewerToolbar.jsder Host‑Anwendung laden. docViewerinitialisieren und das resultierendeobjViewerbehalten.- Jedes lizensierte Such‑ oder Annotations‑Ribbon initialisieren.
attach(objViewer)für jedes Ribbon aufrufen.- Das Dokument öffnen und sein Token für Viewer‑ und Modul‑Anfragen behalten.
Doconut.TestApp.Distributed behält diese exakte UI‑Zusammensetzung und denselben Viewer‑Toolbar‑Helper bei. Sein zusätzlicher access‑Request‑Wert und die asynchron‑Render‑Retry‑Einstellungen gehören zum verteilten Transport; sie ändern nicht, wie Viewer, Toolbar 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. 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 Leisten 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 und Annotationen für die vollständige, funktionsspezifische Einrichtung oder Benutzerdefinierte Themen, um die host‑eigene Viewer‑Toolbar zu stylen oder zu ersetzen.
Dokument öffnen
Die Serverseite besteht aus einem einzigen Endpunkt: Der injizierte Viewer‑Dienst öffnet das Dokument und gibt ein Sitzungstoken zurück.
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 ruft dieses Token ab 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 Sitzung, gibt die Rendering‑Engine frei, löscht deren Sicherheitsmarker und widerruft das Token. Das gleitende Ablaufdatum führt schließlich dieselbe Bereinigung durch, aber ein explizites Schließen wird bei großen Dokumenten empfohlen.
Der vollständige 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: Protokollieren Sie es niemals, speichern Sie es nicht, übergeben Sie es ausschließlich dem Widget. Es identifiziert eine aktive Dokumentsitzung auf dem Server und funktioniert nicht mehr, 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 dargestellt, mit einer Miniaturansicht‑Leiste links. Sollte dies nicht der Fall sein, siehe Troubleshooting.
Was Sie ohne Lizenz erhalten
Fehlt eine Lizenz, wird kein Fehler ausgelöst. Der Viewer rendert normal, jedoch enthält jede Seite ein Evaluations‑Wasserzeichen. Siehe License Setup für Informationen darüber, wie Doconut eine Lizenz findet und welche Änderungen danach auftreten.
War diese Seite hilfreich?