Rychlý start

Vykreslete svůj první dokument během několika minut

Tento průvodce vezme aplikaci ASP.NET Core z prázdného Program.cs až po dokument vykreslený v prohlížeči: registraci serveru, kompletní balíček Vieweru (panel nástrojů Vieweru, připojení Vieweru a volitelné pásky Vyhledávání/Anotace), odkazy na zdroje, inicializaci klienta, otevření dokumentu a spuštění.

Hostitelská aplikace musí cílit na runtime, který podporuje netstandard2.1 — .NET Core 3.0 nebo novější. Referenční aplikace dodávané s tímto vydáním cílí na net8.0.

Nastavení serveru

AddDoconut() registruje služby; UseDoconutResources() a UseDoconut() propojují middleware. Volání zdrojů musí přijít jako první. Volání sezení jsou také vyžadována — výchozí zabezpečení dokumentu Doconut ověřuje každý požadavek stránky proti stavu ASP.NET sezení. Stav sezení potřebuje mezipaměť: AddDistributedMemoryCache() ji poskytuje. Aplikace MVC nebo Razor Pages ji již registruje, ale aplikace minimal-API ne, a bez ní se aplikace při spuštění zastaví s Unable to resolve service for type 'IDistributedCache'. Už jste během Instalace zaregistrovali Doconut? Přeskočte na další sekci.

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
});
builder.Services.AddDistributedMemoryCache(); // session state potřebuje mezipaměť (MVC/Razor Pages již přidávají jednu)
builder.Services.AddSession(); // Zabezpečení dokumentů Doconut vychází z ASP.NET session state

app.UseSession();          // Zavolejte UseSession() před UseDoconut()
app.UseDoconutResources(); // musí být zaregistrováno před UseDoconut()
app.UseDoconut();

Referenční aplikace zachovává historický tvar požadavku DocImage.axd a připojuje middleware dokumentu na odpovídající větev. Toto je uspořádání, které je třeba zkopírovat, když posouváte existující aplikaci .NET Standard dál, protože klient nadále volá stejnou URL, kterou vždy používal:

csharp
builder.Services.AddDoconut(options =>
{
    options.UnsafeMode      = false;   // ponechte Doconut's kontrolu relace povolenou
    options.ShowDoconutInfo = false;
});
builder.Services.AddDistributedMemoryCache(); // session state potřebuje mezipaměť (MVC/Razor Pages již přidávají jednu)
builder.Services.AddSession(options =>
{
    options.IdleTimeout        = TimeSpan.FromSeconds(3600);
    options.Cookie.HttpOnly    = true;
    options.Cookie.IsEssential = true;
});

// Vyžadováno pro vícebytové kódování v některých formátech dokumentů.
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

app.UseStaticFiles();
app.UseRouting();
app.UseSession();
app.UseDoconutResources();   // PŘED větví dokumentu
app.MapWhen(
    context => context.Request.Path.Value?.EndsWith("DocImage.axd", StringComparison.OrdinalIgnoreCase) == true,
    branch => branch.UseDoconut());

UseDoconut() nepřijímá žádné možnosti v tomto vydání — vše bylo přesunuto do AddDoconut().

MiddlewarePath je koordinační hodnota; sama o sobě nepřiřazuje větev ASP.NET Core. ResourcesPath poskytuje vložený balík na /doconut-res a cesta k obrázkovému zdroji widgetu je tedy ResPath: 'doconut-res/images'.

Přidejte viewer na stránku

Viewer je požadovaným jádrem stránky. Jeho vykreslovací plocha používá dva vnořené div:

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

Zacházejte s panelem nástrojů, připojeními modulů a povrchem Vieweru jako s jednou stránkovou kompozicí. Vyhledávání a Anotace vkládají své vložené pásky do volitelných připojení, ale tyto moduly nejsou nikdy samostatné: vždy se připojují k Vieweru na stejné stránce.

html
<nav id="toolbar" aria-label="Document viewer controls">
    <!-- Tlačítka navigace prohlížeče, zoom, Search a Annotation -->
</nav>

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

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

Odkaz na prostředky prohlížeče

V Razor pohledu injektovaná služba Viewer vydává značky <link> a <script> prohlížeče ve správném pořadí závislostí — widget je jQuery plugin, takže jQuery musí být načteno před skripty prohlížeče:

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
}))

Pro kompletní balíček Vieweru požádejte o prostředky Vieweru a modulů najednou:

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 a IncludeViewerScripts jsou povinné základní příznaky. Nikdy nepublikujte příklad Search nebo Annotation Ribbon bez nich, umístění Vieweru a instance docViewer. ReferenceCss a ReferenceScripts vynechávají prostředky volitelného modulu, pokud aktuální licence tuto funkci nepovoluje; základní Viewer se stále spustí.

Tyto volání nahrazují ručně zkopírované soubory skriptů. Pokud aplikace stále načítá své vlastní docViewer.js, documentLinks.js nebo docViewer.UI.js, odstraňte tyto značky, jakmile stránka funguje s vydanými prostředky — viz průvodce migrací.

Inicializace prohlížeče

Klientský widget je jQuery plugin. Toto je minimální sada skutečných init možností (ne pseudokódu):

javascript
let searchBar = null;
let annBar = null;

const objViewer = $('#div_ctlDoc').docViewer({
    showThumbs: true,
    autoLoad:   false,
    pageZoom:   100,
    FitType:    'width',
    BasePath:   '/',
    ResPath:    'doconut-res/images',
    onViewerReady: function () {
        // stránky jsou viditelné; je bezpečné skrýt indikátor načítání zde
    },
    // Přeposílat události životního cyklu anotací do vložené pásky, pokud je přítomna.
    onAnnLoaded:    () => annBar?.handleAnnLoaded(),
    onAnnSaved:     () => annBar?.handleAnnSaved(),
    onAnnSaveError: () => annBar?.handleAnnSaveError(),
    onAnnClosed:    () => annBar?.handleAnnClosed(),
    onError: function (message) {
        console.error('Doconut viewer error:', message);
    }
});

Dva detaily rozhodují, zda tato stránka vůbec funguje:

  • Callbacky jsou možnosti. onViewerReady, onViewerBusy, onCopy a onAutoLoadStatus jsou předány v objektu možností. Předchozí viewer odvozoval názvy globálních funkcí z ID kontejneru a volal je; tento ne. Handler deklarovaný pouze jako globální funkce se nikdy nespustí a nic se nehlásí.
  • ResPath ukazuje na předponu prostředků, nikoli na kořen aplikace. S výchozím ResourcesPath je tato hodnota doconut-res/images. Pokud jste změnili ResourcesPath, použijte vlastní předponu.

Obě tyto selhávají tiše — viz Řešení problémů a průvodce migrací.

Psaní možností je skutečně smíšené — showThumbs, autoLoad a pageZoom jsou ve stylu camelCase, ale FitType, BasePath a ResPath jsou ve stylu PascalCase. Neexistuje konzistentní pravidlo; pokud napíšete špatně, možnost je tiše ignorována (widget se vrátí k výchozímu nastavení místo vyhození chyby).

Sestavení kompletního balíčku Vieweru

Obě referenční aplikace nainstalují následující části společně na jedné stránce:

Část balíčkuPožadavekJak je připojeno
Prostředky Vieweru, připojení a objViewerVyžadovánoJádrový vykreslovač dokumentu
Panel nástrojů VieweruVyžadováno v referenční kompoziciHost markup; tlačítka volají stejný objViewer
Vyhledávací pásVolitelný, licencovaný moduldoconutSearchBar(...).attach(objViewer)
Anotační pásVolitelný, licencovaný moduldoconutAnnotationBar(...).attach(objViewer)

Ačkoliv hlavní panel nástrojů Vieweru je host markup, je instalován spolu s Viewerem a nikdy by neměl být dokumentován jako samostatná kontrola. To udržuje jeho rozvržení, popisky, ikony a autorizační pravidla pod kontrolou vaší aplikace, zatímco každé tlačítko ovládá stejnou instanci Vieweru:

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>

Udržujte pořadí inicializace balíčku používané oběma referenčními aplikacemi:

  1. Vydávejte CSS pro Viewer a licencované moduly.
  2. Vykreslete panel nástrojů Vieweru, montáže Search/Annotation a montáž Vieweru společně.
  3. Vydávejte skripty pro Viewer a licencované moduly.
  4. Načtěte pomocný skript panelu nástrojů host aplikace.
  5. Inicializujte docViewer a uchovejte vzniklý objViewer.
  6. Inicializujte každý licencovaný Search nebo Annotation Ribbon.
  7. Zavolejte attach(objViewer) na každém Ribbon.
  8. Otevřete dokument a uchovejte jeho token pro požadavky Vieweru a modulů.

Serverové ochrany jsou důležité: když je volitelná schopnost nedostupná, její skript není vydán, takže její jQuery plug‑in funkce neexistuje.

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>

Obě vložené komponenty generují svůj vlastní Ribbon DOM. Search obsahuje skupiny Najít, Možnosti a Výsledky. Annotation obsahuje své nástroje pro tvorbu, ovládací prvky stylu, akce uložení a volitelné akce exportu/obrázku. Tyto lišty vystavují open(), close(), reset() a isOpen(); vždy zavolejte attach(objViewer) jednou po jejich vytvoření.

Ukázka výše vynechává volitelné host callbacky a koncové body exportu/obrázku pro Annotation, aby byl start co nejmenší. Viz Vyhledávání a Anotace pro kompletní nastavení specifické pro funkci, nebo Vlastní motivy pro stylování nebo nahrazení panelu nástrojů Vieweru vlastněného hostem.

Otevřít dokument

Serverová strana je jeden koncový bod: injektovaná služba Viewer otevírá dokument a vrací token relace. Otevírání je v tomto vydání asynchronní.

csharp
app.MapPost("/api/open", async (Viewer viewer) =>
{
    // Token je neprůhledný — předávej ho widgetu, nikdy ho neloguj ani neukládej.
    string token = await viewer.OpenDocumentAsync("wwwroot/files/Sample.pdf");
    return Results.Ok(new { token });
});

Klient získá tento token a předá jej widgetu pomocí objViewer.View(token):

javascript
fetch('/api/open', { method: 'POST' })
    .then(resp => resp.json())
    .then(data => {
        currentToken = data.token;
        objViewer.View(currentToken);
    });

Před prvním otevřením není nic, co by se mělo připravovat. Pokud aplikaci posouváte dál, odstraňte jakékoli volání InitCache() a příslušný příznak — metoda již neexistuje.

Zavřít dokument

Zavolejte objViewer.Close(), když uživatel opustí prohlížeč nebo otevře nahrazující dokument. V serverově řízených pracovních postupech viewer.CloseDocument(token) okamžitě odstraní uloženou relaci, uvolní vykreslovací engine, smaže jeho bezpečnostní značku a zruší token. Posuvná expirace nakonec provede stejný úklid, ale pro velké dokumenty se doporučuje explicitní zavření.

Dokončený tok požadavku je:

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

Zacházejte s tokenem jako s přístupovým oprávněním: nikdy jej nezaznamenávejte, nikdy neukládejte, předávejte jej pouze widgetu. Identifikuje aktivní relaci dokumentu na serveru a přestane fungovat, když tato relace vyprší — znovu otevřete dokument a získáte nový.

Spusťte to

Umístěte PDF na wwwroot/files/Sample.pdf, spusťte dotnet run a otevřete stránku, která hostí widget. První stránka se vykreslí v prohlížeči s panelem miniatur na levé straně. Pokud se tak nestane, podívejte se na Řešení problémů.

Co získáte bez licence

Chybějící licence nevyvolá výjimku. Prohlížeč se vykresluje normálně, ale každá stránka nese vodoznak hodnocení. Viz Nastavení licence pro informace, jak Doconut najde licenci a co se změní, až ji najde.

Byla tato stránka užitečná?