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, klientinitiering, dokumentöppning och körning.

Serverinställning

AddDoconut() registrerar tjänsterna; UseDoconutResources() och UseDoconut() kopplar middleware. Resurs‑anropet måste komma först. Session‑anropen krävs också — Doconut:s standarddokument‑säkerhet validerar varje sidförfrågan mot ASP.NET‑sessionsstatus. Sessionsstatus behöver en cache: AddDistributedMemoryCache() tillhandahåller en. En MVC‑ eller Razor‑Pages‑app registrerar den redan, men en minimal‑API‑app gör det inte, och utan den stannar appen vid start med Unable to resolve service for type 'IDistributedCache'. 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.AddDistributedMemoryCache(); // session state behöver en cache (MVC/Razor Pages lägger redan till en)
builder.Services.AddSession(); // Doconut-dokumentsäkerhet bygger på ASP.NET session state

app.UseSession();          // anropa UseSession() innan UseDoconut()
app.UseDoconutResources(); // måste registreras innan UseDoconut()
app.UseDoconut();

För en produktionsliknande sökvägslayout, 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, "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 är ett koordineringsvärde; det mappar inte en ASP.NET Core‑gren i sig självt. I detta exempel mappar värden /doconut, så klienten använder BasePath: 'doconut'. ResourcesPath levererar det inbäddade paketet på /doconut-res, och widgetens bildresurs‑sökväg är därför ResPath: 'doconut-res/images'. Skriv båda utan inledande snedstreck: viewern lägger till ett själv, så '/doconut' skulle bli //doconut/DocImage.axd, vilket webbläsaren tolkar som en begäran till en värd som heter doconut, och viewern misslyckas med "Viewer‑hanteraren kunde inte nås".

Lägg till viewern på en sida

Viewer är den nödvändiga kärnan på sidan. Dess renderingsyta använder två nästlade divs:

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 Annotation injicerar sina inbäddade band i valfria monteringar, men dessa moduler är aldrig fristående: de fäster 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-navigering, zoom, sökning och annoteringsknappar -->
</nav>

<div id="searchBarMount"></div>
<div id="annBarMount"></div>

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

Referera till viewer‑resurserna

I en Razor‑vy, den injicerade Viewer‑tjänsten genererar viewer‑<link> och <script>‑taggar i beroendeordning — widgeten är ett jQuery‑plugin, så jQuery måste laddas innan viewer‑skripten:

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‑flaggorna. Publicera aldrig ett Sök‑ eller Annotation‑Band‑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 startar ändå.

Initiera visaren

Klient‑sidans widget är ett jQuery‑plugin. Detta är en minimal uppsättning faktiska initieringsalternativ (inte pseudokod):

javascript
let searchBar = null;
let annBar = null;

const objViewer = $('#div_ctlDoc').docViewer({
    showThumbs: true,
    autoLoad:   false,
    pageZoom:   100,
    FitType:    'width',
    BasePath:   'doconut',             // ingen inledande '/'
    ResPath:    'doconut-res/images',  // ingen inledande '/'
    onViewerReady: function () {
        // sidorna är synliga; säkert att dölja en laddningsindikator här
    },
    // Vidarebefordra annoteringslivscykelhändelser till den inbäddade ribbon när den är närvarande.
    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 versaliseringen fel så 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 objViewerKrävsKärndokumentrenderare
Viewer‑verktygsfältKrävs i referenssammanställningenVärdmarkering; knappar anropar samma objViewer
SökbandValfritt, licensierad moduldoconutSearchBar(...).attach(objViewer)
AnnoteringsbandValfritt, licensierad moduldoconutAnnotationBar(...).attach(objViewer)

Även om huvud‑Viewer‑verktygsfältet är värdmarkering, 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 till 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älpen och dess <nav id="toolbar">‑markering tillsammans när du kopierar den fullständiga demoinställningen.

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, Search/Annotation‑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 Search‑ eller Annotation‑Ribbon.
  7. Anropa attach(objViewer) på varje Ribbon.
  8. Öppna dokumentet och behåll dess token för Viewer‑ och modul‑förfrågningar.

Doconut.TestApp.Distributed behåller exakt denna UI‑sammansättning och samma Viewer‑verktygsfältshjälp. 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 Ribbons sätts ihop.

Server‑sidans skydd är viktiga: när en valfri funktionalitet är otillgänglig, genereras inte dess skript, 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 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. Staplarna 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 enda endpoint: den injicerade Viewer‑tjänsten öppnar dokumentet och returnerar en sessionstoken.

csharp
app.MapPost("/api/open", async (Viewer viewer) =>
{
    // Token är opak — ge den till widgeten, logga eller spara den aldrig.
    string token = await viewer.OpenDocumentAsync("wwwroot/files/Sample.pdf");
    return Results.Ok(new { token });
});

Klienten hämtar 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 serverstyrda 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.

Den 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 den 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 innehåller 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 renderar 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 hjälpsam?