クイックスタート

MVC 5 または Web Forms で最初のドキュメントをレンダリングする

このハンドブックでは、.NET Framework 4.7.2 上の ASP.NET アプリケーションを、インストールされたパッケージからブラウザでレンダリングされたドキュメントへと導きます:Global.asax、オープンエンドポイント、ビューアのアセット、ウィジェット、そしてそれらを結びつけるトークンです。Web.config の登録が Installation に従って設定されていることを前提としています — DocImage.axd ハンドラとリソースモジュールがなければ、以下の処理はサーバーに到達できません。

Global.asax で Doconut を構成する

A complete Application_Start for an MVC 5 application:

csharp
// Global.asax.cs - compose once per worker process, release on shutdown.
protected void Application_Start()
{
    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

    Doconut.DoconutHost.Initialize(options =>
    {
        options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
        options.UnsafeMode  = false; // a page is served only to the session that opened the document
    });

    // MVC only: keep the two Doconut endpoints out of routing.
    RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    RouteTable.Routes.IgnoreRoute("doconut-res/{*pathInfo}");
}

protected void Application_End()
{
    Doconut.DoconutHost.Shutdown();
}
  • Encoding.RegisterProvider は、一部のドキュメント形式が使用するレガシーコードページをプロセスで利用できるようにします。最初のドキュメントを開く前に一度だけ呼び出してください。
  • UnsafeMode = false はデフォルト設定で、誤って変更されないよう明示しています。DocImage.axd はドキュメントを開いた ASP.NET セッションにのみページを提供します。
  • 2つの IgnoreRoute 呼び出しは、DocImage.axd と /doconut-res/* への MVC ルーティングを防ぎます。これらはハンドラとモジュールが提供します。Web Forms アプリケーションには MVC ルートがないため、この行は不要です。
  • DoconutHost.Shutdown は、アプリケーションプールがリサイクルされる際に Doconut のバックグラウンド作業を停止し、サービスを解放します。Initialize が実行されていなくても安全に呼び出せます。

ドキュメントを開く

ドキュメントを開くと不透明なトークンが返されます。ウィジェットはそのトークンを各ページリクエストに添えて送信します。

MVC 5 では、コントローラアクションが DoconutHost.Services から Viewer サービスを解決します — MVC 5 にはコンストラクタインジェクションがありません:

csharp
// POST /Document/Open
[HttpPost]
public async Task<ActionResult> Open()
{
    var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();

    // The token is opaque - hand it to the viewer, never log or persist it.
    string token = await viewer.OpenDocumentAsync(Server.MapPath("~/files/Sample.pdf"));
    return Json(new { token });
}

ドキュメントは セッションステートを持つリクエスト内で 開く必要があります。これは、ドキュメントを開くことが現在の ASP.NET セッションにページへのアクセス権を付与するためです。MVC コントローラと Web Forms ページはデフォルトでセッションステートを保持します。カスタム IHttpHandler は System.Web.SessionState.IRequiresSessionState を実装しない限りセッションステートを持ちません。ハンドラからセッションステートなしでドキュメントを開くと、ビューアはすべてのページで「You Are Not Authorized To View This Page.」と表示します。

Web Forms では、ページ自身がコードビハインドでドキュメントを開くことができます。OpenDocument は OpenDocumentAsync の同期版で、非同期ページを使用しないコードビハインド向けに用意されています:

csharp
// Default.aspx.cs
protected string Token;

protected void Page_Load(object sender, EventArgs e)
{
    var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();
    Token = viewer.OpenDocument(Server.MapPath("~/files/Sample.pdf"));
}

トークンはベアラ資格情報のように扱い、決してログに残したり永続化したりしないでください。ウィジェットにのみ渡します。ドキュメントセッションが期限切れになるとトークンは機能しなくなるので、再度ドキュメントを開いて新しいトークンを取得してください。

ビューア資産の参照

Viewer.ReferenceCss と Viewer.ReferenceScripts は、埋め込み資産用の <link> と <script> タグを依存順に生成し、/doconut-res/ を指します。ウィジェットは jQuery プラグインなので、jQuery が最初に読み込まれます。

MVC 5. ビューには @inject がないため、コントローラでタグを生成し、ViewBag に渡します:

csharp
public ActionResult Index()
{
    var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();
    ViewBag.ViewerCss = viewer.ReferenceCss(new CssConfig
    {
        IncludeBootstrapCss = true,
        IncludeViewerCss    = true
    });
    ViewBag.ViewerScripts = viewer.ReferenceScripts(new ScriptConfig
    {
        IncludeJQuery        = true,
        IncludeBootstrap     = true,
        IncludeViewerScripts = true
    });
    return View();
}
html
@Html.Raw(ViewBag.ViewerCss)
...
@Html.Raw(ViewBag.ViewerScripts)

この処理はコントローラに残しておきます。MVC 5 はビューを最初に提供するときにコンパイルし、追加のコンパイラパッケージが無い場合、そのコンパイラは C# 5 しか理解できません — ?. も $"..." も nameof も使用できません。これらを使用したビューは Visual Studio では正常にコンパイルされますが、ブラウザでは空の 500 エラーが返ります。

Web Forms. コードビハインドから同じ文字列を公開し、<%= %> で書き出します:

html
<head>
    <%= ViewerCss %>
</head>
<body>
    ...
    <%= ViewerScripts %>
</body>

IncludeViewerCss と IncludeViewerScripts は必須のコアです。Search と Annotation のリボンを追加するには、IncludeSearchCss、IncludeAnnotationCss、IncludeSearchScripts、IncludeSearchBar、IncludeAnnotationScripts、IncludeAnnotationBar も設定します。ライセンスがその機能を許可していない場合、両方の方法ともリボンのファイルを省略しますが、ビューア自体は起動します。

ページにビューアを追加する

レンダリング領域は 2 つの入れ子になった div です:

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

外側の div に実際の高さを設定します — ビューアはコンテナを埋め、開始時にそのサイズを測定します。ビューアは独自のツールバーを描画しません:GotoPage、Next、Zoom、FitType などは、ページ側でボタンに割り当てるメソッドで、ビューアの横に配置します:

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

ビューアを初期化してドキュメントを表示する

ビューアのスクリプトの後でウィジェットを作成し、トークンを渡します:

javascript
var objViewer = $('#div_ctlDoc').docViewer({
    showThumbs: true,
    autoLoad:   false,
    pageZoom:   100,
    FitType:    'width',
    BasePath:   '/',                   // '/' means DocImage.axd at the site root
    ResPath:    'doconut-res/images',  // no leading '/'
    onViewerReady: function () {
        // pages are visible; hide a loading indicator here
    },
    onError: function (message) {
        console.error('Doconut viewer error:', message);
    }
});

fetch('/Document/Open', { method: 'POST' })
    .then(function (resp) { return resp.json(); })
    .then(function (data) { objViewer.View(data.token); });

Web Forms では、ページ自体がドキュメントを開く場合、最後の 3 行は objViewer.View('<%= Token %>'); に置き換えます。

ここでの 4 つの詳細はエラーメッセージなしで失敗します:

  • BasePath: '/' はサイトルートの DocImage.axd を指します。仮想ディレクトリ内のアプリケーションの場合、スラッシュなしで名前を使用します('myapp' は /myapp/DocImage.axd を要求)。先頭にスラッシュがあると('/myapp')//myapp/DocImage.axd となり、ブラウザは別ホストへのリクエストと解釈します。
  • ResPath: 'doconut-res/images' — アイコンはリソースルートの下のフォルダにあります。'doconut-res' を使用すると、すべてのアイコンが 404 を返し、ツールバーのグリフやロードスピナーが表示されませんが、ドキュメント自体はレンダリングされます。先頭にスラッシュを付けると BasePath と同様に壊れます。
  • コールバックはオプションです。 onViewerReady、onError などは docViewer(...) に渡すオブジェクトの中に記述します。ctlDoc_ViewerReady のようにビューア名で付けたグローバル関数は呼び出されません。
  • ビューアを保持し、別途 View を呼び出す。 docViewer(...) は Zoom、Next、FitType などのメソッドを持つオブジェクトを返し、View(...) は別のものを返します。var objViewer = $('#div_ctlDoc').docViewer({...}).View(token) とするとドキュメントは表示されますが、最初のツールバーボタンをクリックしたときに objViewer.Zoom is not a function エラーが発生します。

オプション名は camelCase(showThumbs、autoLoad、pageZoom)と PascalCase(FitType、BasePath、ResPath)が混在しています。綴りミスしたオプションは無視され、ウィジェットはデフォルト設定を使用します。

ワンラインの代替手段

ページがドキュメントの表示だけを必要とし、独自のツールバーが不要な場合、Viewer.RenderViewer は初期化スクリプト全体—docViewer(...) に BasePath: '/' と ResPath: 'doconut-res/images' を設定し、続いて .View(token) を呼び出す—を書き出します。この機能はこのパッケージにのみ存在します:

csharp
// Web Forms code-behind, after opening the document
ViewerInit = viewer.RenderViewer("div_ctlDoc", Token);
html
<div id="div_ctlDoc" style="height: 100vh"></div>
<%= ViewerScripts %>
<%= ViewerInit %>

ViewerConfig を3番目の引数として渡すことで、ズーム、フィット、サムネイルパネルを変更できます。生成されたスクリプトはビューアへの参照を保持しないため、ページに独自のツールバーが必要な場合は上記の手書き初期化を使用してください。

ドキュメントを閉じる

ユーザーがビューアから離れるか別のドキュメントを開くときは objViewer.Close(true) を呼び出します。これによりウィジェットがクリアされ、DocImage.axd にクローズリクエストが送信されます。引数なしの objViewer.Close() はウィジェットだけをクリアします。サーバー側では viewer.CloseDocument(token) がドキュメントセッションを即座に削除し、レンダリングリソースを解放し、セッションのページへのアクセス権を取り消します。スライディング有効期限でも最終的に同様の処理が行われますが、大きなドキュメントを明示的に閉じることでメモリが早く解放されます。

実行方法

~/files/Sample.pdf に PDF を配置し、IIS Express でサイトを起動します(Visual Studio の F5)。ウィジェットをホストするページを開くと、左側にサムネイルが表示された状態で最初のページがレンダリングされます。表示されない場合は トラブルシューティング を参照してください。

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

ライセンスが無くても例外は発生しません。ビューアは通常通りレンダリングしますが、すべてのページに評価用の透かしが付加されます。Doconut がライセンスを探す場所については ライセンス設定 をご覧ください。

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