Snabbstart
Rendera ditt första dokument på några minuter
Denna genomgång tar en ASP.NET Core-app från en tom Program.cs till ett dokument som renderas i webbläsaren: serverregistrering, det kompletta Viewer‑paketet (Viewer‑verktygsfält, Viewer‑montering och valfria Search/Annotation‑band), resursreferenser, klientinitialisering, dokumentöppning och körning.
Serverinställning
AddDoconut() registrerar tjänsterna; UseDoconutResources() och UseDoconut() kopplar middleware. Anropet till resurserna måste komma först. Session‑anropen krävs också — Doconut:s standarddokument‑säkerhet validerar varje sidförfrågan mot ASP.NET‑sessions‑state. Har du redan registrerat Doconut under Installation? Hoppa vidare till nästa avsnitt.
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 en produktionsliknande sökvägs‑layout, mappa dokument‑middleware till en explicit gren och håll de fyra sökvägsinställningarna i linje:
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 är ett koordineringsvärde; det mappar inte en ASP.NET Core‑gren i sig. I detta exempel mappar värden /doconut, så klienten måste använda BasePath: '/doconut'. ResourcesPath levererar det inbäddade paketet på /doconut-res, och widgetens bildresurs‑sökväg blir därför ResPath: '/doconut-res/images'.
Lägg till visaren på en sida
Viewer är den nödvändiga kärnan på sidan. Dess renderingsyta använder två nästlade div‑element:
<div id="divDocViewer">
<div id="div_ctlDoc"></div>
</div>Behandla verktygsfältet, modul‑monteringarna och Viewer‑ytan som en enda sidkomposition. Search och Annotation injicerar sina inbäddade band i valfria monteringar, men dessa moduler är aldrig fristående: de fästs alltid på Viewer på samma sida. Använd samma ordning som Doconut.TestApp och 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>Referera till visarens resurser
I en Razor‑vy emitterar den injicerade Viewer‑tjänsten visarens <link>‑ och <script>‑taggar i beroendeordning — widgeten är ett jQuery‑plugin, så jQuery måste laddas innan visarskript:
@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 det kompletta Viewer‑paketet, begär Viewer‑ och modulresurserna tillsammans:
@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 och IncludeViewerScripts är de obligatoriska kärn‑flaggan. Publicera aldrig ett Search‑ eller Annotation‑Ribbon‑exempel utan dem, Viewer‑monteringen och en docViewer‑instans. ReferenceCss och ReferenceScripts utelämnar ett valfritt moduls resurser när den aktuella licensen inte ger den möjligheten; kärn‑Viewer startas ändå.
Initiera visaren
Klient‑side‑widgeten är ett jQuery‑plugin. Detta är en minimal uppsättning faktiska init‑alternativ (inte pseudokod):
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);
}
});Alternativens versalisering är faktiskt blandad — showThumbs, autoLoad och pageZoom är camelCase, men FitType, BasePath och ResPath är PascalCase. Det finns ingen konsekvent regel; om du får fel versalisering ignoreras alternativet tyst (widgeten återgår till standardvärdet istället för att kasta ett fel).
Sätt ihop det kompletta Viewer‑paketet
Båda .NET 8‑referensapplikationerna installerar följande delar tillsammans på en sida:
| Del av paketet | Krav | Hur den är ansluten |
|---|---|---|
Viewer‑resurser, montering och objViewer | Krävs | Kärndokument‑renderare |
| Viewer‑verktygsfält | Krävs i referenskompositionen | Värd‑markup; knappar anropar samma objViewer |
| Search‑band | Valfri, licensierad modul | doconutSearchBar(...).attach(objViewer) |
| Annotation‑band | Valfri, licensierad modul | doconutAnnotationBar(...).attach(objViewer) |
Även om huvud‑Viewer‑verktygsfältet är värd‑markup, installeras det tillsammans med Viewer och får aldrig dokumenteras som en fristående kontroll. Detta håller dess layout, etiketter, ikoner och auktoriseringsregler under din applikations kontroll medan varje knapp styr samma Viewer‑instans:
<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>Det fullständiga referensverktygsfältet kopierar också wwwroot/js/viewerToolbar.js in i värdapplikationen för rotation, miniatyr, utskrift, helskärm, layout och knapp‑tillstånd‑hjälpare. Ladda den värdfilen efter Viewer.ReferenceScripts(...). Håll hjälparen och dess <nav id="toolbar">‑markup tillsammans när du kopierar den fullständiga demo‑implementeringen.
Behåll paketets initieringsordning som används av båda referensapplikationerna:
- Emitera Viewer-, Search- och Annotation‑resurser tillsammans.
- Rendera Viewer‑verktygsfältet, Ribbon‑monteringarna och Viewer‑monteringen tillsammans.
- Initiera
docViewerförst. - Skapa varje licensierad Ribbon och fäst den till samma
objViewer. - Öppna dokumentet och behåll dess token för modul‑förfrågningar.
Doconut.TestApp.Distributed behåller exakt denna UI‑komposition och samma Viewer‑verktygsfältshjälpare. Dess extra access‑förfrågningsvärde och asynkrona render‑retry‑inställningar tillhör den distribuerade transporten; de ändrar inte hur Viewer, verktygsfält eller Ribbons sätts ihop.
Server‑sidans skydd är viktiga: när en valfri funktionalitet inte är tillgänglig, emitteras dess skript inte, så dess jQuery‑plugin‑funktion existerar inte.
<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>Båda inbäddade komponenterna genererar sin egen Ribbon‑DOM. Search innehåller grupperna Find, Options och Results. Annotation innehåller sina författarverktyg, stilkontroller, spara‑åtgärder och valfria export‑/bild‑åtgärder. Balkarna exponerar open(), close(), reset() och isOpen(); anropa alltid attach(objViewer) en gång efter att de skapats.
Exemplet ovan utelämnar valfria värd‑callback‑funktioner och Annotation‑export‑/bild‑slutpunkter för att hålla uppstarten minimal. Se Sök och Annotationer för den kompletta funktionsspecifika konfigurationen, eller Anpassade teman för att styla eller ersätta det värdeägda Viewer‑verktygsfältet.
Öppna ett dokument
Server‑sidan är en endpoint: den injicerade Viewer‑tjänsten öppnar dokumentet och returnerar en session‑token.
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 });
});Klienten hämtar den token och överlämnar den till widgeten med objViewer.View(token):
fetch('/api/open', { method: 'POST' })
.then(resp => resp.json())
.then(data => {
currentToken = data.token;
objViewer.View(currentToken);
});Stäng dokumentet
Anropa objViewer.Close() när användaren lämnar visaren eller öppnar ett ersättningsdokument. Vid server‑styrda arbetsflöden tar viewer.CloseDocument(token) omedelbart bort den cachade sessionen, frigör renderingsmotorn, raderar dess säkerhetsmarkör och återkallar token. Glidande utgång utför så småningom samma städning, men explicit stängning rekommenderas för stora dokument.
Det färdiga begäranflödet är:
AddDoconut + middleware
-> render CSS/scripts and mount div
-> initialize docViewer
-> OpenDocumentAsync
-> return opaque token
-> objViewer.View(token)
-> page/search/annotation requests
-> Close / CloseDocumentBehandla token som en bärar‑behörighet: logga den aldrig, lagra den aldrig, överlämna den endast till widgeten. Den identifierar en aktiv dokumentsession på servern och slutar fungera när sessionen löper ut — öppna dokumentet igen för att få en ny.
Kör det
Placera en PDF på wwwroot/files/Sample.pdf, kör dotnet run och öppna sidan som hostar widgeten. Den första sidan renderas i visaren, med en miniatyrpanel till vänster. Om den inte gör det, se Felsökning.
Vad du får utan licens
En saknad licens kastar inte ett fel. Visaren renderas normalt, men varje sida har ett utvärderings‑vattenstämpel. Se Licensinställning för hur Doconut hittar en licens och vad som förändras när den gör det.
Var den här sidan till hjälp?