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.

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ägs‑layout, 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. 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:

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

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 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 paketetKravHur den är ansluten
Viewer‑resurser, montering och objViewerKrävsKärndokument‑renderare
Viewer‑verktygsfältKrävs i referenskompositionenVärd‑markup; knappar anropar samma objViewer
Search‑bandValfri, licensierad moduldoconutSearchBar(...).attach(objViewer)
Annotation‑bandValfri, 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 auktoriseringsregler 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. Emitera Viewer-, Search- och Annotation‑resurser tillsammans.
  2. Rendera Viewer‑verktygsfältet, Ribbon‑monteringarna och Viewer‑monteringen tillsammans.
  3. Initiera docViewer först.
  4. Skapa varje licensierad Ribbon och fäst den till samma objViewer.
  5. Ö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.

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 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.

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

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 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?