
ビューアはステートレス — .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");
});
コードの動作概要
- ファイル名を受け取る – クライアントはサーバーに
wwwroot/files配下のどのファイルを開くか指示します。 OpenDocumentAsyncを呼び出す – ステートレスなViewerが新しいセッションを作成し、キャッシュに保存し、不透明なトークンを返します。- トークンをプレーンテキストで返す – クライアントはトークンだけを受け取り、サーバーはこのレスポンスでドキュメントのバイトを送信しません。
Viewer はドキュメントデータを保持しないため、エンドポイントは using ブロックや Dispose 呼び出し、リクエストごとのファクトリを必要としません。トークンはクライアントがビューアウィジェット(フロントエンドの objViewer.View(token))に返す唯一の認証情報です。
クライアント側でのトークン使用
トークンが返された後、フロントエンドウィジェットは objViewer.View(token) を呼び出します。ウィジェットはその後、ページ画像、検索、注釈操作の各リクエストに同じトークンを含めます。サーバーはトークンを、最初にドキュメントを開いたセッションと照合して検証します。別のブラウザセッションからトークンが提示された場合、ビューアは認可エラーを返し、これが意図されたセキュリティ動作です。
セッションの早期クローズ(オプション)
ワークフローでドキュメントが再度アクセスされないことが分かっている場合、Viewer 上で CloseDocument を呼び出してキャッシュエントリを解放できます。これによりセッションがキャッシュから削除され、スライディング有効期限タイマーが保持し続けることを防ぎます。
ステートレスフローのまとめ
| ステップ | 何が起こるか | 状態の保存場所 |
|---|---|---|
| Viewer の注入 | 起動時に単一の Viewer インスタンスが作成されます。 | DI コンテナ内(シングルトン)。 |
| OpenDocumentAsync | ライセンスがチェックされ → セッションが作成され → トークンが返されます。 | セッションは IMemoryCache に保存されます(または分散キャッシュ)。 |
| クライアントの描画 | ウィジェットは各リクエストにトークンを送信します。 | トークンはクライアントが保持する唯一のドキュメント単位データです。 |
| セッションの期限切れ / CloseDocument | タイムアウトまたは明示的なクローズ後にキャッシュエントリが削除されます。 | Viewer サービスに残存リソースはありません。 |
サービス自体がドキュメントデータを保持しないため、Web ファームを安全にスケールアウトしたり、ノードを交換したり、アプリケーションを再起動してもユーザーに見える状態を失うことはありません。トークンだけが無効になり、クライアントはドキュメントを再度開くよう促されます。
アプリへのステートレスビューアのデプロイ
AddDoconut、AddSession、およびキャッシュプロバイダーをProgram.csに追加します。- オープンエンドポイントのスニペットをミニマル API 設定に貼り付けます。
- 返されたトークンをフロントエンドの
objViewer.View(token)に渡します。
これで、Doconut の Viewer 設計を活用した、完全にステートレスで本番環境対応のドキュメントオープン API が手に入ります。