クイックスタート

数分で最初のドキュメントをレンダリング

このハウツーでは、空の Program.cs から始める ASP.NET Core アプリを、ブラウザーでドキュメントが表示されるまで導きます。サーバー登録、完全な Viewer パッケージ(Viewer ツールバー、Viewer マウント、オプションの検索/注釈リボン)、アセット参照、クライアント初期化、ドキュメントのオープン、そして実行です。

サーバー設定

AddDoconut() はサービスを登録します。UseDoconutResources()UseDoconut() はミドルウェアを接続します。リソース呼び出しは最初に行う必要があります。セッション呼び出しも必須です — Doconut のデフォルトドキュメントセキュリティは、すべてのページリクエストを ASP.NET セッション状態と照合して検証します。すでに インストール 時に Doconut を登録しましたか?次のセクションへ進んでください。

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();

プロダクション向けのパスレイアウトの場合、ドキュメントミドルウェアを明示的なブランチにマップし、4 つのパス設定を揃えておきます:

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 は調整用の値であり、単体で ASP.NET Core のブランチをマップするものではありません。この例ではホストが /doconut にマップしているため、クライアントは BasePath: '/doconut' を使用する必要があります。ResourcesPath は埋め込みバンドルを /doconut-res で提供し、ウィジェットの画像リソースパスはそのため ResPath: '/doconut-res/images' となります。

ページにビューアを追加

Viewer はページに必須のコアです。その描画領域は 2 つの入れ子になった div を使用します:

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

ツールバー、モジュールマウント、Viewer の表面を 1 つのページ構成として扱います。Search と Annotation は埋め込みリボンをオプションのマウントに注入しますが、これらのモジュールは単体で使用されることはなく、常に同じページの Viewer に添付されます。Doconut.TestAppDoconut.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>

ビューア資産を参照

Razor ビューでは、注入された Viewer サービスが依存順序でビューアの <link><script> タグを出力します — ウィジェットは jQuery プラグインであるため、viewer スクリプトの前に jQuery を読み込む必要があります:

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

完全な Viewer パッケージを取得するには、Viewer とモジュールのリソースを一緒にリクエストします:

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

IncludeViewerCssIncludeViewerScripts は必須のコアフラグです。これら、Viewer マウント、そして docViewer インスタンスなしで Search や Annotation リボンの例を公開しないでください。ReferenceCssReferenceScripts は、現在のライセンスがその機能を許可していない場合、オプションモジュールのリソースを省略しますが、コア Viewer は起動します。

ビューアを初期化

クライアント側ウィジェットは jQuery プラグインです。以下は実際の初期化オプションの最小セットです(疑似コードではありません):

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

オプションのケースは実際に混在しています — showThumbsautoLoadpageZoom は camelCase、FitTypeBasePathResPath は PascalCase です。一貫したルールはなく、ケースが間違っているとオプションは黙って無視され(ウィジェットは例外を投げずにデフォルトにフォールバックします)。

完全な Viewer パッケージを組み立てる

.NET 8 のリファレンスアプリケーションは、以下のパーツを 1 ページにまとめてインストールします:

パッケージの部分要件接続方法
Viewer リソース、マウント、そして objViewer必須コアドキュメントレンダラー
Viewer ツールバー参照構成で必須ホストマークアップ;ボタンは同じ objViewer を呼び出す
検索リボンオプション、ライセンス済みモジュールdoconutSearchBar(...).attach(objViewer)
注釈リボンオプション、ライセンス済みモジュールdoconutAnnotationBar(...).attach(objViewer)

メインの Viewer ツールバーはホストのマークアップですが、Viewer と一緒にインストールされ、単独のコントロールとして文書化してはいけません。これにより、レイアウト、ラベル、アイコン、認可ルールがアプリケーション側で管理され、すべてのボタンが同じ Viewer インスタンスを操作します:

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>

完全なリファレンスツールバーは、回転、サムネイル、印刷、全画面、レイアウト、ボタン状態ヘルパー用に wwwroot/js/viewerToolbar.js をホストアプリケーションにコピーします。Viewer.ReferenceScripts(...) の後にそのホストファイルを読み込んでください。フルデモ実装をコピーする際は、ヘルパーとその <nav id="toolbar"> マークアップを一緒に保管してください。

両方のリファレンスアプリケーションで使用されているパッケージ初期化順序を維持してください:

  1. Viewer、Search、Annotation のリソースを一緒に出力する。
  2. Viewer ツールバー、リボンマウント、Viewer マウントを一緒に描画する。
  3. まず docViewer を初期化する。
  4. 各ライセンス済みリボンを作成し、同じ objViewer に添付する。
  5. ドキュメントを開き、モジュールリクエスト用にトークンを保持する。

Doconut.TestApp.Distributed はこの正確な UI 構成と同じ Viewer ツールバーヘルパーを保持しています。追加の access リクエスト値と非同期レンダーリトライ設定は分散トランスポートに属し、Viewer、ツールバー、リボンの組み立て方法には影響しません。

サーバー側のガードは重要です。オプション機能が利用できない場合、そのスクリプトは出力されず、jQuery プラグイン関数も存在しません。

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>

埋め込みコンポーネントはそれぞれ独自のリボン DOM を生成します。Search には Find、Options、Results のグループがあり、Annotation には作成ツール、スタイルコントロール、保存アクション、オプションのエクスポート/画像アクションが含まれます。各バーは open()close()reset()isOpen() を提供し、作成後は必ず一度だけ attach(objViewer) を呼び出してください。

上記の例では、起動を最小限に抑えるためにオプションのホストコールバックや Annotation のエクスポート/画像エンドポイントは省略しています。完全な機能別設定については 検索注釈 を参照するか、ホスト所有の Viewer ツールバーをスタイル変更または置き換えるには カスタムテーマ をご覧ください。

ドキュメントを開く

サーバー側は 1 つのエンドポイントで、注入された Viewer サービスがドキュメントを開き、セッショントークンを返します。

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

クライアントはそのトークンを取得し、objViewer.View(token) でウィジェットに渡します:

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

ドキュメントを閉じる

ユーザーがビューアを離れるか別のドキュメントを開く際は objViewer.Close() を呼び出してください。サーバー駆動のワークフローでは、viewer.CloseDocument(token) がキャッシュされたセッションを即座に削除し、レンダリングエンジンを破棄し、セキュリティマーカーを削除し、トークンを無効化します。スライディング有効期限でも最終的に同様のクリーンアップが行われますが、大きなドキュメントの場合は明示的なクローズが推奨されます。

完了したリクエストフローは次のとおりです:

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

トークンはベアラークレデンシャルとして扱い、決してログに記録したり永続化したりせず、ウィジェットにのみ渡してください。サーバー上のライブドキュメントセッションを識別し、セッションが期限切れになると機能しなくなります — 新しいトークンを取得するにはドキュメントを再度開いてください。

実行方法

wwwroot/files/Sample.pdf に PDF を配置し、dotnet run を実行してウィジェットをホストするページを開きます。最初のページがビューアに表示され、左側にサムネイルパネルが表示されます。表示されない場合は、トラブルシューティング を参照してください。

ライセンスなしで得られるもの

ライセンスがない場合でも例外は発生しません。ビューアは通常通りレンダリングされますが、すべてのページに評価用の透かしが付加されます。Doconut がライセンスを取得する方法と取得後の変更点については、ライセンス設定 を参照してください。

このページは役に立ちましたか?