-
Notifications
You must be signed in to change notification settings - Fork 0
MS_ASPNETStateManagement
- 戻る(ASP.NET)
- ASP.NETの状態管理方式
- ASP.NET Session / ASP.NET ViewState
2 層 C/S システムでは、クライアント側プログラムが DB に直接接続し、
状態(プログラムが処理に必要とする一連の情報。
制御情報や業務処理に必要な情報を含む)を一元管理するという方式が
採用されている。
これに対し 3 層 C/S システムや Web システムでは、
AP サーバの拡張性・信頼性を確保するために、
サーバの状態を保持しないで「サーバへのリクエスト」・
「クライアントへのレスポンス」の間で必要な情報を持ち回り、
サーバがリクエストを受け付けたときサーバ側で状態を復元する
という方式が一般化した(一般的に、サーバに状態を保持しないほうが
拡張性は高くなる。サーバに状態を保持した場合、
信頼性を確保するための冗長化構成が組み難いなどの問題があるため)。
しかし、近年の Web システムにおいては、サーバに状態を保持した場合も
拡張性・信頼性を確保するための技術
(Session 情報をリモート プロセス・リモート サーバなどで
一元管理するためのインフラストラクチャの構築技術)も登場しており、
サーバ側のメモリ領域にユーザ毎に確保される
「Session」を使用して、
状態を保持するケースが多数を占めるようになってきている。
このため、3 層 C/S システムや Web システムの「状態管理方式」の大枠は、
次の 2 つの方式に分けることができる。
表1:3層C/SシステムやWebシステムの状態管理方式
| 項番 | 状態管理方式 | 説明 |
|---|---|---|
| 1 | サーバ ステートレス | サーバ側の状態保持領域を利用しない。 |
| 2 | サーバ ステートフル | サーバ側の状態保持領域を利用する。 |
特に Web システムの「状態管理方式」は、
クライアント側で状態を一元管理することができないため、
クライアント側とサーバ側の双方で連携して状態を管理する必要があり、
2 層・3 層 C/S アプリケーションと比べて複雑である。
このため、本ドキュメントでは Web アプリケーション用の AP サーバである
ASP.NET を使用した ASP.NET アプリケーションの「状態管理方式」に関する、
下記の項目について説明する。
- ASP.NET アプリケーションの一般的な「状態管理方式」
- ASP.NET アプリケーションの開発で使用可能な「状態管理技術」
- 実装上の考慮点
- 性能の考慮点
- 拡張性・信頼性を確保するための、負荷分散(冗長化)構成を組む際の考慮点
特に、「状態管理方式」の選択や「状態管理技術」の使い方を誤れば、
性能の悪化や保守性の悪化、予期せぬセキュリティ問題が発生したり、
拡張性・信頼性の要件が満たせないという問題などにも
結びついたりするので注意が必要である。
「サーバ ステートレスな状態管理方式」とは
Web・AP サーバに状態を持たせない方式であり、
必要なデータは DB サーバ上に永続化するか、クライアント・サーバ間で
HTTP のリクエスト ⇒ レスポンス ⇒ リクエストと状態を持ち廻る方式である。
この場合、サーバはリクエストを処理してレスポンスを返した段階で
Web・AP サーバ上のメモリの情報を破棄し、
Web・AP サーバ上に状態を保持しない。

表:サーバ ステートレスな状態管理方式の処理概要
| 順番 | クライアント / サーバ | モジュール | 処理 |
|---|---|---|---|
| 1 | クライアント側 | www ブラウザ | 「サーバ処理1」に対して「ページ1」を要求する。 |
| 2 | サーバ側 | サーバ処理1 | 「ページ1」の HTML をクライアントに出力する。 |
| 3 | クライアント側 | www ブラウザ ページ1 |
「Form」や「クエリー ストリング」に処理を継続するために必要な情報を含め「サーバ処理2」を要求する。 |
| 4 | サーバ側 | サーバ処理2,3 | 「サーバ処理2」⇒「サーバ処理3」と情報を持ち廻る時は、「Form」・「HTTP Context」などに情報を格納した後にサーバ処理を遷移し、「ページ2」の HTML をクライアントに出力する。 |
「サーバ ステートフルな状態管理方式」とは
Web・AP サーバに状態を持たせる方式であり、
必要なデータを Web・AP サーバ上のメモリ領域に保持する。

この方式では、Web・AP サーバ上のメモリ領域に状態を保持する
(主に Session が使用される)。
このため、保持すべきデータを DB サーバ上に永続化したり、
クライアント・サーバ間で状態を持ち廻ったりしなくても、
画面間で情報を引き継ぐことができる。
また、「サーバ ステートレスな状態管理方式」で使用した技術も併用できる。
表:ASP.NETにおける状態管理技術の説明
| 項番 | 状態管理技術 | 説明 |
|---|---|---|
| 1 | Formデータ | HTTP のメッセージ ボディを使用する。送信時は Form のポストで送信する。受信時は HTML として受信する。 |
| 2 | ViewState | Hidden を使用した状態保持の仕組みだが、ASP.NET 独自の基盤機能が付加されている。 |
| 3 | Query string | HTTP のリクエストのメッセージ ヘッダーを使用する。 |
| 4 | Cookie | HTTP のメッセージ ヘッダーを使用する。 |
| 5 | Server.Transfer +HTTP Context領域 |
Server.Transfer 処理はサーバ処理を遷移するためのメソッド、HTTP Context 領域はリクエスト単位で確保する領域である。ASP.NET 独自の呼称だが、似たような仕組みは各 AP サーバにも用意されている。 |
| 6 | Session | ASP.NET の組込みオブジェクト。ASP.NET 独自の基盤機能が付加されている。 |
| 7 | Application | ASP.NET の組込みオブジェクト。アプリケーション単位の共通情報を管理する。 |
| 8 | 静的変数 | ASP.NET プログラムのグローバル変数。 |
| 9 | Cache | ASP.NET の組込みオブジェクト。キャッシュ処理用に使用される。 |
表:ASP.NETにおける状態管理技術の特徴
| 項番 | 状態管理技術 | ASP.NET独自 | Webアプリ一般 | ステートレス | ステートフル |
|---|---|---|---|---|---|
| 1 | Formデータ | - | ○ | ○ | - |
| 2 | ViewState | ○ | - | ○ | - |
| 3 | Query string | - | ○ | ○ | - |
| 4 | Cookie | - | ○ | ○ | - |
| 5 | Server.Transfer+HTTP Context領域 | - | ○ | ○ | - |
| 6 | Session | ○ | - | - | ○ |
| 7 | Application | ○ | - | - | ○ |
| 8 | 静的変数 | - | ○ | - | ○ |
| 9 | Cache | ○ | - | - | ○ |
移行メモ(誤字): 元ページの
ViewStateの説明は
「Hidden を仕様した状態保持の仕組み」となっているが、
「使用した」の誤記である(ASP.NET ViewStateも同様)。
ASP.NET が、今までの Web 開発技術から大きく進化した点に、
VB6.0 以前のバージョンや .NET の Windows アプリケーションなどで
知られている「イベント ドリブンのプログラミング モデル」が
採用された点が挙げられる。
この「イベント ドリブンのプログラミング モデル」を可能にしたことで、
ASP.NET では、「同一の画面に対してポストバックする方式」が標準となった。
「同一の画面に対してポストバックする方式」とは、
自身を生成した画面(aspx)に対して Form 情報をポストする方式のことである。

ASP.NET では、画面上でボタンを押すと自分の画面に対して
「Form 情報」が「ポストバック」される。
サーバ側では、画面上のどのボタンが押されたのかを「Form 情報」から
自動的に解析し、画面に登録されているイベント ハンドラに
自動的に処理を振り分ける。
このように、従来の技術と比べ ASP.NET では
「動的ページ」と「サーバ処理」の関係が、
「画面」という単位でわかりやすく対応付くようになった。
また、従来の技術では同一画面を再表示する場合、
ポストされた「Form 情報」をサーバ側で再取得して、
再び HTML の各要素の value に設定して出力する必要があったが、
ASP.NET の Web コントロールでは、
Web コントロールの情報をサーバ側で復元する処理も自動化されている。
ASP.NET 独自のサーバ ステートレスな状態管理技術として
「ViewState」がある。
-
「ViewState」の実装
- レスポンス時に「ViewState」に設定されたオブジェクトを
シリアライズし、これにハッシュ値を付与したデータを
base64 エンコードして、name/id属性が__VIEWSTATEに
設定された Hidden タグに保存する。 - リクエスト時は、逆の操作で
__VIEWSTATEの Hidden タグのデータを
base64 デコードし、ハッシュ値を検証した後に
データをデシリアライズしてオブジェクトとして復元する。
ハッシュ値の付与や base64 エンコードを除けば、
オブジェクトのデータをシリアライズ・デシリアライズし、
Hidden タグを使用して文字列形式で情報を保持しているだけである。
このため、「ViewState」はサーバ ステートレスな状態管理技術に
分類できる(設定によっては暗号化も可能であるが、
デフォルトの設定では暗号化されないので注意が必要である)。 - レスポンス時に「ViewState」に設定されたオブジェクトを
-
「ViewState」の利用目的
- イベント ドリブンのプログラミング モデルを可能にした
ASP.NET のアプリケーション基盤技術としての利用 - 同一画面内でのみ機能する(画面間を跨った利用は不可能)、
サーバ ステートレスな状態管理技術としての利用
- イベント ドリブンのプログラミング モデルを可能にした
「ViewState」には、イベント ドリブンのプログラミング モデルを
実現するための使用方法が存在する。
この用途では、利用者から意図することなく利用される。
Web コントロールに関する表示状態の情報を ViewState に保存することで
「ポストバック」の際に、
-
Web コントロールの情報を、サーバ側で復元する。
通常のテキスト ボックスなどの Web コントロールのデータは、
「ViewState」を OFF にしても復元されるが、
グリッド ビュー コントロールなどの Web コントロールに
データ バインドしたデータは、
「ViewState」を OFF にした場合、復元されなくなる。 -
クライアント側で何が行われたのかをサーバ側で自動解析し、
Web コントロールの change イベント ハンドラに自動的に処理を振り分ける。
Web コントロール毎にイベント名が異なるが、
TextBox コントロールにはTextChangedイベント、
ListBox コントロールにはSelectedIndexChangedイベントなどがある。

移行メモ(イベント名): 元ページは TextBox のイベントを
「TextChange イベント」と記しているが、正しくはTextChangedである。
前項に示した使用方法以外には、同一画面内でのみ機能する
(画面間を跨った利用は不可能)、
サーバ ステートレスな状態管理技術としての使用方法がある。
この使用方法では、利用者が必要に応じてアプリケーションに実装する。
独自に「Hidden タグ」を追加して、そこにシリアル化された
オブジェクト情報を保持する方式と大きな違いは無い。
Web フォームのメンバ変数は、Windows フォーム内のメンバ変数のように
情報を保持しない。また、サーバ ステートレスな状態管理方式を
採用している場合、サーバ側のメモリも利用できない。
このような場合に「ViewState」を使用すれば、
同一画面内でのみ状態を保持することができる。
このため、見方によっては Web フォーム内の情報を保持する機構と
解釈することもできる。

また、サーバ ステートフルな状態管理方式を採用している場合、
Web フォーム内の情報を保持する処理を「Session」でも
代替できるが、「ViewState」の場合は
データ消去の手間がかからないというメリットがある。
- 独自の値を追加する、Base64 デコードして値を確認する。
-
EnableViewStateで有効/無効の制御。 - なお、暗号化には署名と暗号化があり、双方とも ON/OFF が可能である。
-
EnableViewStateMac(署名・改ざん検証) -
ViewStateEncryptionMode(暗号化)
-
参考(iPentec)
- [C#] ViewState に独自の値を保存する
https://www.ipentec.com/document/document.aspx?page=csharp-asp-net-save-original-value-in-viewstate - [C#] ViewState の値の文字列をデコードして解析する
https://www.ipentec.com/document/document.aspx?page=csharp-asp-net-viewstaet-decode - [C#] ASP.NET の ViewState を無効にする
https://www.ipentec.com/document/document.aspx?page=csharp-asp-net-disabled-viewstate - [C#] ViewStateMode の違いによる動作の違い
https://www.ipentec.com/document/document.aspx?page=csharp-aspnet-viewstatemode - [ASP.NET] ASP.NET の ViewState 値の文字列の暗号化を無効にする
https://www.ipentec.com/document/document.aspx?page=asp-net-viewstate-value-crypt-disabled
移行メモ(最新化:
EnableViewStateMacは無効化できない):
MS14-059 / .NET 4.5.2 以降、EnableViewStateMac="false"は
無視され、常に MAC 検証が行われる(設定しても例外になる)。
ViewState の署名を外すと任意のオブジェクトを送り込まれ、
デシリアライズによる RCE(リモート コード実行) に直結するためである。
設定 現在 EnableViewStateMac常に有効(無効化不可) ViewStateEncryptionMode任意( Alwaysにすると値も秘匿できる)machineKeyの自動生成キーの漏洩= RCE。値を公開資料に載せない 実際、
machineKeyが漏れた(サンプルの値をそのまま使った)ことによる
ViewState 経由の攻撃が繰り返し報告されている。
後述の「負荷分散構成でのmachineKey統一」は必要な設定だが、
その値の管理は極めて機微であると理解しておきたい。
「ViewState」を利用する際、最も注意しなければならない点は、
「クライアント側にダウンロードされる HTML データが膨張し、
ネットワーク トラフィックが増加して性能劣化に繋がる可能性がある」
という点である。
繰り返すが、「ViewState」は、イベント ドリブンのプログラミング モデルを
可能にする ASP.NET のアプリケーション基盤技術である。
このため、意図的に利用していなくても、
Web フォームが HTML を出力する際に影ながら利用されてしまう。
例えば、読み取り専用のグリッド ビュー コントロールに表示データを
データ バインドし、クライアントに出力したとする。すると、
ASP.NET の基盤処理により、自動的にデータ グリッド コントロールの
表示状態の情報を「ViewState」に出力してしまう。
ある事例では、**1MB の HTML テーブル データに対し 1MB の「ViewState」**が
出力され、実際にクライアント側にダウンロードされる HTML データが
2 倍の 2MB に膨れ上がり、ネットワーク トラフィックが増加して
性能劣化に繋がった。

この事例のグリッド ビュー コントロールは読み取り専用であったため、
change イベント ハンドラなどへの振り分けは必要なかった。
適切な対策としては、グリッド ビュー コントロールの「ViewState」機能を
無効に設定し、DB 上のデータを再度取得するなどの方式が挙げられる。
「ViewState」を、Web フォーム内の情報を保持する機構として利用した場合も、
大容量のデータを「ViewState」に保持した場合は、
クライアント側にダウンロードされる HTML データが膨張し
ネットワーク トラフィックが増加して性能劣化に繋がる。
ある事例では、ドロップ ダウン リスト コントロールなどに
データ バインドするマスタ データの DataSet オブジェクトや
DataTable オブジェクトなどを「ViewState」に保存して、
HTML データが膨張し性能劣化に繋がった。
適切な対策としては、DB 上のデータを再度取得したり、
「Session」・「Cache」に格納した情報を
利用したりする方式が挙げられる。
「ViewState」のデータ自体は、ただの「Hidden データ」として
埋め込まれることを意識し、
クライアント側にダウンロードされる HTML データが膨張し、
ネットワーク トラフィックが増加して
性能劣化に繋がることがないように注意を払う。
データを「ViewState」に保持するより、DB 上のデータを再度取得するか
「Session」に格納した情報を利用する方が、
処理効率は良い可能性がある。また、DB 上のデータを再度取得する
オーバーヘッドが問題となる場合で、データがマスタ データであれば、
「Cache」を使用しても良い。
特に、ADO.NET の DataSet / DataTable オブジェクトなどを
データ バインド可能な Web コントロールが出力する「ViewState」は、
巨大になる傾向がある。以下にデータ バインド可能な Web コントロールを
列挙しておく。
-
GridView、Repeater、ListBox -
CheckBoxList、RadioButtonList DropDownList
また、
- Web コントロールの情報を、サーバ側で復元する。
- クライアント側で何が行われたのかをサーバ側で自動解析し、
Web コントロールの change イベント ハンドラなどに
自動的に処理を振り分ける。
などの処理がそもそも不要な Web コントロールに対しては、
「ViewState」の機能を停止し
(該当する Web コントロールの EnableViewState プロパティを
false に設定する)、クライアント側にダウンロードされる
HTML データの膨張を抑止することも検討する。
補足(
ViewStateModeを使う): ASP.NET 4.0 以降は
ViewStateModeにより、
「ページ全体は無効、必要なコントロールだけ有効」という
オプトイン方式が取れる。<%@ Page ViewStateMode="Disabled" %> ... <asp:GridView ID="gv" runat="server" ViewStateMode="Enabled" />
EnableViewStateViewStateMode親で無効にしたとき 子で有効に戻せない 子で Enabledにできる「既定は切っておき、要るところだけ入れる」という運用ができるため、
本項の対策としては現在こちらが実用的である。
-
サーバにデータを保持しないことによるメリット
- サーバ リソースの消費量が少なく、拡張性に優れる。
- サーバ リソース(メモリ)の領域計算が容易である。
- サーバ リソース(メモリ)の解放タイミング
(タイムアウトを含む)を考慮する必要がない。 - 拡張性・信頼性を確保するための、負荷分散(冗長化)構成が容易である。
-
クライアントにデータがダウンロードされることによるデメリット
- ネットワーク トラフィックが問題になる。
-
持ち回りデータの改ざんが可能なため、
セキュリティを確保するのに都合が悪いことがある。
-
プログラミングの難易度
- 必要なデータの引継ぎ処理に関する設計・実装が多くなる。
- 「
Server.Transfer処理と HTTP Context 領域の組合せ」などの
ASP.NET の標準的な画面遷移方法以外の、
新規ウィンドウ オープンや URL 直打ちなどの特殊な操作に
対応することが比較的容易である。
-
クライアントにデータがダウンロードされないことによるメリット
- ネットワーク トラフィックを軽減できる。
- データを持ち回る必要がなく、改ざんのリスクが無いため、
セキュリティを確保するのに都合が良い。
-
サーバにデータを保持することによるデメリット
- サーバ リソースの消費量が多いため、拡張性に乏しい。
- サーバ リソース(メモリ)が枯渇しないように、領域計算が必要になる。
- サーバ リソース(メモリ)の解放タイミング
(タイムアウトを含む)を考慮する必要がある。 - 拡張性・信頼性を確保するための、
負荷分散(冗長化)構成を工夫する必要がある。
-
プログラミングの難易度
- 必要なデータの引継ぎ処理に関する実装が少なくて済む。
- 特殊な画面遷移に対応する必要がある場合、
ユーザ プログラムで Session 内の状態を判定し、
処理を振り分けるなどして、これらに対応できるように設計する必要がある。
サーバ ステートフルな状態管理技術なので、
「サーバ ステートフルな状態管理技術の共通的な特徴」に示した特徴を持つ。
クライアントのブラウザが Web サーバに接続したタイミングで、
サーバがクライアントに返す「SessionID(基本的に Cookie を利用)」を
利用することにより、それ以降の接続でユーザの Session を識別できるようになり、
Web サーバ上のメモリ上にユーザ毎の「Session」を使用できる。
-
長所
- 画面を跨って状態を管理する「状態管理技術」の中では
最も手軽に利用できる。また、API からも非常に簡単に使用できる。 - 「Cookie」が利用できない環境でも、
Cookie-less session を使用すれば「Session」を使用できる
(URL に「SessionID」が追加される)。
- 画面を跨って状態を管理する「状態管理技術」の中では
-
短所
- 基本的には、シリアル化ができないオブジェクトも格納できるが、
ステート サービス・ステート データベース(後述)を使用する場合は、
シリアル化可能なオブジェクトしか格納できなくなるので、
拡張性を確保する必要があるならば、
シリアル化可能なオブジェクトのみ格納する。 - 以下の式により、
[1 台の Web サーバ上で使用される Session 領域の容量] を計算し、
他のサービスなどが使用するメモリなども考慮した上で、
メモリ使用量が許容量以下に抑えられるよう計算して使用する必要がある。
- 基本的には、シリアル化ができないオブジェクトも格納できるが、
[ユーザ1人あたりが使用するSession領域の容量] × [1台のWebサーバが処理するユーザ数]
= [1台のWebサーバ上で使用されるSession領域の容量]
メモリ使用量の許容量
- サーバの物理メモリの使用量としては 90% 以下であるが、
32bit 環境では、ASP.NET の .NET Framework が使用できる
仮想メモリ量は別に決められているため、
[1 台の Web サーバ上で使用される Session 領域の容量] は、
これ以下の使用量である必要がある。 - ASP.NET の .NET Framework が使用できるメモリ量は、
.NET の設定にあるmemoryLimit要素で指定される。
この要素のデフォルト値は 60%(サーバの物理メモリ容量の 60%)と
なっており、サーバの物理メモリ容量が 4GB である場合、
デフォルトの仮想メモリ量は 4GB × 0.6 = 2.4GB となる。 - このため、物理メモリ容量が大きいサーバでは、
ASP.NET のアプリケーションの使用できる仮想メモリ量が、
ASP.NET のワーカ プロセスの仮想アドレス空間の上限に近づく
(若しくは上回る)ことがあるので注意する。
一般的な環境のユーザ モードの仮想アドレス空間の上限は 2GB である
(WOW64を参照)。
移行メモ(最新化:
memoryLimitは IIS 6 以降ほぼ使われない):
processModel/@memoryLimitは IIS 5 互換モード用の設定であり、
IIS 6 以降(ワーカ プロセス分離モード)では
アプリケーション プールの「リサイクル」設定
(プライベート メモリ制限、仮想メモリ制限)が使われる。
また 64bit 環境が標準となった現在、
「ユーザ モード仮想アドレス空間 2GB」という上限も該当しない。ただし、「Session の容量 × 同時ユーザ数を見積もる」という
本項の考え方自体は現在も必要である
(インプロセス Session はメモリを食い、
プールのリサイクルで消える)。
サーバ ステートフルな状態管理技術なので、
「サーバ ステートフルな状態管理技術の共通的な特徴」に示した特徴を持つ。
-
長所
- アプリケーションで共有されるデータを効率よく保存できる。
- 採番テーブルの採番プール化などに役立つ。
-
短所
- 排他制御が必要になり、使い難い(再現性の低いバグを造り込み易い)。
- ネットワーク負荷分散(冗長化)の構成ノードで共有する仕組みがない。
サーバ ステートフルな状態管理技術なので、
「サーバ ステートフルな状態管理技術の共通的な特徴」に示した特徴を持ち、
更に「Application」にキャッシングに必要な
アプリケーション基盤機能を実装したような特徴を持っている。
-
長所
- キャッシングに必要なアプリケーション基盤機能が実装されている。
- メモリ不足を自動検出して、データを破棄する機能を持つ。
- 日付情報から自動的にデータを破棄する機能を持つ。
- ファイルの書き換えを自動検出し、自動的にデータを破棄する機能を持つ。
- 他のオブジェクトの書き換えを自動検出し、
自動的にデータを破棄する機能を持つ。 - 性能や拡張性の向上を実現できる
(「Cache」は、サーバ側の状態管理技術であるが、
負荷分散(冗長化)構成を組む際の問題とはならない)。
-
短所
- 排他制御が必要になり、使い難い(再現性の低いバグを造り込み易い)。
- 主に常数データに利用する。更新されるデータの保持には向かない。
- 実装に熟練した技術者が必要になる。
- 利用前に、null チェックが必要。
- 長所に列挙した機能自体を使いこなすことが難しい。
- キャッシュ データを構築する処理を 1 スレッドにして排他を掛ける必要がある。
補足(Cache が「冗長化の問題にならない」理由): Session と違い、
Cache は「無くても DB から作り直せる」データを置く場所だからである。
ノードごとに中身が違っていても正しく動作する
(その分、キャッシュ ヒット率はノード数で割られる)。
逆に、更新されるデータを Cache に置くと
ノード間で食い違って再現性の低いバグになる。
本項が「主に常数データに利用する」としているのはこのためである。
共有が要るなら Redis 等の分散キャッシュを使う。
サーバ ステートレスな状態管理技術なので、
「サーバ ステートレスな状態管理技術の共通的な特徴」に示した特徴を持つ。
-
長所
- API から非常に簡単に使用できる。
- ハッシュを使用した改ざん防止機能がある。
-
短所
- ASP.NET は「同一の画面に対してポストバックする方式」を採用しているため、
そもそも Form データ(Hidden 項目を含む)を次画面に引き継げない。 - ASP.NET 2.0 で、クロスページ ポストバックにより
Web コントロールの情報の「一部」を別ページに引き継ぐこともできるように
なったが、「ViewState」による Web コントロールの復元はされない。 -
デフォルトでは暗号化されず、base64 エンコードをデコードすれば
解読可能。プロパティの設定を変更すれば暗号化可能になる。 - 「ViewState」に格納したデータは base64 エンコード後のテキスト データとして
Hidden タグに保存されるため、バイト配列化するために
シリアル化可能なオブジェクトしか格納できない。
- ASP.NET は「同一の画面に対してポストバックする方式」を採用しているため、
サーバ ステートレスな状態管理技術なので、
「サーバ ステートレスな状態管理技術の共通的な特徴」に示した特徴を持ち、
また、主に固定データの持ち廻りに使用される
(更新用の API も用意されているため、可変データの持ち廻りも可能である)。
このため、アプリケーション基盤技術である、
- ユーザ毎の「Session」を識別するための「SessionID」
- 認証基盤が発行する「認証チケット」
などの情報を持ち廻る用途にも利用されている。
それ以外に、パーソナライズ状態の維持
(ログインされていない状態でも、ユーザを識別した状態で画面を表示するなどの
機能のこと。これによりサイトの利便性を向上させることができる)
という用途にも使用される。
拡張性・信頼性を確保するために、負荷分散(冗長化)構成をとるケースがある。

クライアント リクエストは、NLB
(あるいは負荷分散ハードウェア、DNS ラウンドロビン)を用いて
各ノード(Web サーバ)に分散される。
この場合、クライアント リクエストを別のノードへ振り替えられるようにするため、
各ノードは通常サーバ ステートレスである。
特定のノードに障害が発生した場合やメンテナンスのために
サービスを中断する必要がある場合、
クライアント リクエストは自動的に別のノードへと振り替えられる。
バックエンド データ層は、MSCS 上にホストする。
障害が発生した場合やメンテナンスのためにサービスを中断する必要がある場合、
正常なノードがデータへのアクセスを提供し続ける。
ネットワーク負荷分散(冗長化)構成をとる場合、
「状態管理技術」である Session、
ViewState、Cookie
(Forms 認証:暗号化された Cookie 認証チケットを使用する
カスタム認証の実装を支援する ASP.NET の基盤機能)を正しく利用するに当たって、
サーバの構築・設定に特別な配慮が必要になる。
デフォルトの「Session」の設定では、
ASP.NET のホスト プロセスの使用する仮想メモリにデータを格納する
(インプロセス)。
このため、ネットワーク負荷分散(冗長化)構成を組み
各ノードのインプロセスのメモリ領域を使用する場合、
同一クライアントからの要求は、特定のノードへ割り当てる必要がある。
これは、クライアント リクエストがノードを跨いだ場合、
各ノードの同期のとれていない Session を使用してしまうためである。
NLB クラスタの場合、**Affinity パラメタを「単一モード」**に
設定することで、同じクライアント(IP アドレス)から発信された
全ての TCP 接続を、クラスタ内の特定の「物理サーバ」に送ることができる。

上記の問題を回避するために、ASP.NET では「Session」の永続化の専用システム
(ステート サービス・ステート データベースと呼ばれる)を使用して、
プログラムから意識することなくネットワーク負荷分散(冗長化)の
構成ノード共通の「Session」に状態を永続化するインフラの構築が可能である。
表:ステート サービス・ステート データベースの特徴
| 項番 | 状態管理技術 | 説明 |
|---|---|---|
| 1 |
ステート サービス ( StateServer) |
Windows サービスのプロセス上に「Session」のデータを格納する方式。一般的には、専用サーバにステート サービスを持たせる。 |
| 2 |
ステート データベース ( SQLServer) |
SQL Server のストレージ上に「Session」のデータを格納する方式。この場合、専用サーバにステート データベースを持たせる。 |
ステート サービス・ステート データベースを導入した場合、
どのノードからも「クライアント a」に対する「Session-a」が取得可能になる。
この構成では、同一クライアントからの要求を、
同一の Web サーバへ割り当てる必要はない。
このため、ラウンドロビンなど、動的な振り分けにも対応可能になる。

ステート サービス・ステート データベースを利用すると、
同一クライアントからの要求を特定のノードへ割り当てる必要がなくなる。
また、あるノードで障害が発生して構成ノードから切り離されても、
ユーザは「Session」の情報を消失せずに、処理を続行できる。
これにより、Web アプリケーションの信頼性が向上する。

ただし、ステート サービス・ステート データベースを利用した場合、
そこが「単一障害点」になる可能性があるので注意が必要になる。
「単一障害点」を回避するための方法は、
ステート データベースで使用する SQL Server を MSCS、
若しくは SQL Server 2005 SP1 で実装された
データベース ミラーリング機能でクラスタリングすることである。
上記の施策で「単一障害点」を回避できるが、
信頼性を向上させるだけのために MSCS 構成を新規導入するのは、
技術的・予算的に難しい場合が多い。このような場合は、
下記の折衷案を検討するべきである。
- ネットワーク負荷分散(冗長化)の構成を、
同一クライアントからの要求は特定のノードへ割り当てるように構成し、
ノードで障害が発生した際「Session」に保存したデータの消失を許容する
(この場合、業務を再実行する必要がある)。 - 「単一障害点」であるステート サービス・ステート データベースの
復旧を迅速に行う前提で、「単一障害点」を許容する。 -
サーバ ステートレスな設計に変更し、構成ノードがサーバ側の
「状態管理技術」を使用しなくて済むようにする。
補足:障害発生時の「Session」の引継ぎは MSCS 構成でも不可能であるため、
「Session」を他ノードに引き継ぐ場合は MSCS 構成ではなく、
必ずネットワーク負荷分散(冗長化)構成と、
ステート サービス・ステート データベースを構成する必要がある。
これは、MSCS がサーバのメモリ状態をフェイル オーバーする機能を
備えていない為である。MSCS では、共有ディスク上の状態データのみ
引き継ぐことができる。
移行メモ(最新化:現在の選択肢): ステート サービス(
StateServer)は
単一障害点であり冗長化できないため、現在は次を使う。
実行環境 Session の格納先 ASP.NET(Framework) Redis( Microsoft.Web.RedisSessionStateProvider)/ SQL ServerASP.NET Core IDistributedCache(Redis / SQL Server)
(ASP.NET CoreのSession利用方法:MS_ASPNETCoreSession.md)Azure Azure Cache for Redis Redis はレプリケーション構成が組めるため、
本項が指摘する「単一障害点」の問題に直接答えられる。
なお、本ページ執筆時の
「そもそもサーバ ステートレスに設計する」という選択肢が
最も本質的である点は、現在も変わらない
(Azure Kubernetes Service (AKS)のように
Pod が常に入れ替わる環境では特にそうである)。
ステート サービス・ステート データベースに保存される「Session」データ、
Hidden タグに出力される「ViewState」データ、
Forms 認証の基盤機能を使用した場合に発行される「Cookie 認証チケット」は、
各ノードの .NET の設定にある machineKey 要素の情報で
暗号化・検証される(*.configの暗号化:MS_ConfigEncryption.md)。
このため、ネットワーク負荷分散(冗長化)構成を組み、
以下の条件に該当する場合は、
machineKey 要素を構成ノード全体で統一しておく必要がある。
- 同一クライアントからの要求を、特定のノードへ割り当てない設定で
運用する必要がある。 - あるノードで障害が発生して構成ノードから切り離されても、
処理を続行する必要がある。
machineKey 要素を統一することにより、
クライアントのリクエストが別のノードに振り分けられた場合でも、
暗号化された「Session」・「ViewState」・「Cookie 認証チケット」を
復号化・検証できるようになり、処理を続行できる。

- .NET Framework の全般リファレンス > machineKey 要素 (ASP.NET 設定スキーマ)
https://learn.microsoft.com/dotnet/framework/configure-apps/file-schema/web/machinekey-element-aspnet-settings-schema
補足(ASP.NET Core での相当機能): ASP.NET Core には
machineKeyは無く、データ保護 API(Data Protection) が
同じ役割を担う(ASP.NET Coreのデータ保護:MS_ASPNETCoreDataProtection.md)。
ASP.NET(Framework) ASP.NET Core 鍵 machineKey(web.config に記述)キー リング(自動生成・自動失効) 複数ノードで共有 同じ値を全ノードに配る 共有ストアを指す(ファイル共有 / Redis / Blob) 保護 - 証明書 / DPAPI / Key Vault でキー自体を暗号化 services.AddDataProtection() .PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys") .SetApplicationName("MyApp"); // 全ノードで同一にする
SetApplicationNameを揃えないと、
同じ鍵ストアを見ていてもノード間で認証 Cookie を復号できない
(ASP.NET Cookie共有も参照)。
「鍵を全ノードで揃える」という本項の要請そのものは変わっていない。
-
ASP.NET の状態管理の推奨事項
https://learn.microsoft.com/previous-versions/aspnet/z1hkazw7(v=vs.100) -
セッション状態モード
https://learn.microsoft.com/previous-versions/aspnet/ms178586(v=vs.100)
Tags: 移行, .NET開発, ASP.NET, ASP.NET Web Forms
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。