ビューアはステートレス — .NET 8 ミニマルオープンエンドポイントの構築方法
← Back to Blog••2 min read

ビューアはステートレス — .NET 8 ミニマルオープンエンドポイントの構築方法

ビューアはステートレス — 設計上

Viewer は 決して リクエストごとのドキュメントデータを保持しません。これは sealed クラスで、IDisposable を実装することはありません。また、開くすべてのドキュメントはフレームワークのキャッシュが管理する別個のセッションに存在します。そのため、ASP.NET Core アプリの任意の場所で単一の Viewer インスタンスを注入し、複数の同時リクエストから安全に呼び出すことができます。


ステートレスサービスの結果

  • 隠れたリソースはありません – サービス自体は明示的なクリーンアップが必要な大きなバッファを決して割り当てません。
  • デフォルトでスレッドセーフ – リクエスト固有の状態が保存されていないため、同じ Viewer インスタンスをロックなしで複数のスレッドから使用できます。
  • スケーラブルなデプロイ – 水平スケーリングがすぐに利用可能です。スティッキーセッションやサーバーアフィニティは不要で、クライアントが保持するセッショントークンだけが必要です。

すべてのドキュメント固有情報(ページ、注釈、検索インデックス)は OpenDocumentAsync が作成する セッション に保持されます。セッションは IMemoryCache(または構成した任意の IDistributedCache)に保存され、非アクティブ期間(デフォルト 60 分)後に自動的に期限切れになります。完了したら CloseDocument を呼び出してキャッシュエントリを早期に解放できます。


ステートレスビューアの登録

Viewer は可変状態を持たないため、起動時に一度だけ登録します:

builder.Services.AddDoconut();               // Viewer と必要なミドルウェアを登録します
builder.Services.AddSession();               // トークンセキュリティに必要です
builder.Services.AddDistributedMemoryCache(); // デモ用のシンプルなキャッシュ

AddDoconut 呼び出しは、ビューアの静的リソースを提供するミドルウェアも接続します。サービスが設定された後、任意のエンドポイントシグネチャで Viewer を要求できます。


ミニマルなオープンドキュメントエンドポイント(net‑8 例)

以下のコードは公式ドキュメントからの正確なスニペットで、.NET 8 ミニマル‑API プロジェクトですぐに動作します:

app.MapPost("/api/open", async (string fileName, Viewer viewer) =>
{
    var token = await viewer.OpenDocumentAsync($"files/{fileName}");
    return Results.Content(token, "text/plain");
});

コードの動作概要

  1. ファイル名を受け取る – クライアントはサーバーに wwwroot/files 配下のどのファイルを開くか指示します。
  2. OpenDocumentAsync を呼び出す – ステートレスな Viewer が新しいセッションを作成し、キャッシュに保存し、不透明なトークンを返します。
  3. トークンをプレーンテキストで返す – クライアントはトークンだけを受け取り、サーバーはこのレスポンスでドキュメントのバイトを送信しません。

Viewer はドキュメントデータを保持しないため、エンドポイントは using ブロックや Dispose 呼び出し、リクエストごとのファクトリを必要としません。トークンはクライアントがビューアウィジェット(フロントエンドの objViewer.View(token))に返す唯一の認証情報です。


クライアント側でのトークン使用

トークンが返された後、フロントエンドウィジェットは objViewer.View(token) を呼び出します。ウィジェットはその後、ページ画像、検索、注釈操作の各リクエストに同じトークンを含めます。サーバーはトークンを、最初にドキュメントを開いたセッションと照合して検証します。別のブラウザセッションからトークンが提示された場合、ビューアは認可エラーを返し、これが意図されたセキュリティ動作です。


セッションの早期クローズ(オプション)

ワークフローでドキュメントが再度アクセスされないことが分かっている場合、Viewer 上で CloseDocument を呼び出してキャッシュエントリを解放できます。これによりセッションがキャッシュから削除され、スライディング有効期限タイマーが保持し続けることを防ぎます。


ステートレスフローのまとめ

ステップ何が起こるか状態の保存場所
Viewer の注入起動時に単一の Viewer インスタンスが作成されます。DI コンテナ内(シングルトン)。
OpenDocumentAsyncライセンスがチェックされ → セッションが作成され → トークンが返されます。セッションは IMemoryCache に保存されます(または分散キャッシュ)。
クライアントの描画ウィジェットは各リクエストにトークンを送信します。トークンはクライアントが保持する唯一のドキュメント単位データです。
セッションの期限切れ / CloseDocumentタイムアウトまたは明示的なクローズ後にキャッシュエントリが削除されます。Viewer サービスに残存リソースはありません。

サービス自体がドキュメントデータを保持しないため、Web ファームを安全にスケールアウトしたり、ノードを交換したり、アプリケーションを再起動してもユーザーに見える状態を失うことはありません。トークンだけが無効になり、クライアントはドキュメントを再度開くよう促されます。


アプリへのステートレスビューアのデプロイ

  1. AddDoconut、AddSession、およびキャッシュプロバイダーを Program.cs に追加します。
  2. オープンエンドポイントのスニペットをミニマル API 設定に貼り付けます。
  3. 返されたトークンをフロントエンドの objViewer.View(token) に渡します。

これで、Doconut の Viewer 設計を活用した、完全にステートレスで本番環境対応のドキュメントオープン API が手に入ります。

#dotnet8#viewer#stateless#api#doconut#ビューア#ステートレス