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 sök‑/annotationsband), resursreferenser, klientinitialisering, dokumentöppning och körning.

Serverinställning

AddDoconut() registrerar tjänsterna; UseDoconutResources() och UseDoconut() kopplar in 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‑sessionsstatus. Har du redan registrerat Doconut under Installation? Hoppa vidare till nästa avsnitt.

csharp
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ägsstruktur, mappa dokument‑middleware till en explicit gren och håll de fyra sökvägsinställningarna i linje:

csharp
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:

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

Behandla verktygsfältet, modul‑monteringarna och Viewer‑ytan som en enda sidkomposition. Sök‑ och Annotations‑moduler 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:

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>

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:

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 det kompletta Viewer‑paketet, begär Viewer‑ och modulresurserna tillsammans:

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 och IncludeViewerScripts är de obligatoriska kärnflaggan. Publicera aldrig ett exempel på sök‑ eller annotations‑band 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 startar ändå.

Initiera visaren

Klient‑widgeten är ett jQuery‑plugin. Detta är en minimal uppsättning faktiska init‑alternativ (inte pseudokod):

javascript
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 skiftning ä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 skiftningen fel ignoreras alternativet tyst (widgeten återgår till sitt standardvärde istället för att kasta ett fel).

Sätt ihop det kompletta Viewer‑paketet

Båda .NET 6‑referensapplikationerna installerar följande delar tillsammans på en sida:

Del av paketetKravHur det är anslutet
Viewer‑resurser, montering och objViewerObligatorisktKärn‑dokumentrenderare
Viewer‑verktygsfältObligatoriskt i referenskompositionenVärd‑markup; knappar anropar samma objViewer
Sök‑bandValfritt, licensierad moduldoconutSearchBar(...).attach(objViewer)
Annotations‑bandValfritt, licensierad moduldoconutAnnotationBar(...).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 behörighetsregler under din applikations kontroll medan varje knapp styr samma Viewer‑instans:

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>

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:

  1. Generera CSS för Viewer och licensierade moduler.
  2. Rendera Viewer‑verktygsfältet, sök‑/annotations‑monteringar och Viewer‑montering tillsammans.
  3. Generera skript för Viewer och licensierade moduler.
  4. Ladda värdapplikationens viewerToolbar.js.
  5. Initiera docViewer och behåll den resulterande objViewer.
  6. Initiera varje licensierad sök‑ eller annotations‑band.
  7. Anropa attach(objViewer) på varje band.
  8. Öppna dokumentet och behåll dess token för Viewer‑ och 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‑återförsöksinställningar tillhör den distribuerade transporten; de ändrar inte hur Viewer, verktygsfält eller band sätts ihop.

Server‑sidans skydd är viktiga: när en valfri funktionalitet är otillgänglig, genereras dess skript inte, så dess jQuery‑plugin‑funktion finns inte.

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>

Båda inbäddade komponenterna genererar sin egen band‑DOM. Sök‑bandet innehåller grupperna Find, Options och Results. Annotations‑bandet innehåller dess författarverktyg, stilkontroller, spara‑åtgärder och valfria export‑/bild‑åtgärder. Barerna 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 Annotations‑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.

csharp
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):

javascript
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, avvecklar 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äransflödet är:

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

Behandla 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 fel. Visaren renderas normalt, men varje sida har ett utvärderingsvattenstä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?