次の方法で共有


無効な viewstate の問題のトラブルシューティング

この記事では、Microsoft ASP.NET アプリケーションでの viewstate に関する問題をデバッグおよび解決するための手法について説明します。

元の製品バージョン: ASP.NET
元の KB 番号: 829743

はじめに

Viewstate は、サーバーの状態 (セッション状態など) に依存せずにページが自動的に状態を保持できるようにする、ASP.NET の機能です。 ただし、viewstate に関連する問題はデバッグが困難な場合があります。 ほとんどの場合、viewstate に関する問題が発生すると、Web ブラウザーで次のエラー メッセージが表示され、問題の原因はほとんど示されません。

このページのビューステートは無効であり、破損している可能性があります。

この記事では、デバッグや viewstate に関する問題の解決に使用できるいくつかの手法について説明します。

Web ファームで実行している場合は、validationKey 属性を設定します

Web ファームで、各クライアント要求はポストバックごとに異なるコンピューターに移動できます。 この動作のため、validationKey属性を AutoGenerate ファイルにに設定したままにすることはできません。 代わりに、 validationKey 属性の値を、Web ファーム上のすべてのマシンで共有される固定文字列に設定する必要があります。

動的に生成された型を Web ファームの viewstate に格納しない

ASP.NET ファイルを動的にコンパイルすると、ファイルはランダムな名前を持つアセンブリに組み込まれます (たとえば、ファイル名が jp395dun.dll場合があります)。 Web ファームを実行している場合、同じファイルが異なるランダムな名前のアセンブリにコンパイルされます。 通常、これらのアセンブリ名に関する前提は誰も行わないので、問題ではありません。 ただし、バイナリ シリアル化を使用して動的にコンパイルされた型を viewstate に配置した場合、アセンブリの名前は viewstate データの一部として含まれます。 そのビューステートが後で Web ファーム内の別のサーバーに送信されると、ビューステートは異なるアセンブリ名を使用するため、逆シリアル化できません。

最善の解決策は、バイナリ シリアル化の使用を回避する方法です。 バイナリ シリアル化では、この問題が発生しない場合でも、多くのリソースが使用されます。 代わりに、viewstate に入力する内容を、配列、ペア、トリプレット、および単純型 (文字列、int、その他の型など) の組み合わせに制限します。 System.Web.UI.Pair System.Web.UI.Tripletは、ビューステート エンジンが効率的に処理できる単純なラッパー型です。

この問題を回避する別の解決策は、viewstate に格納している型を、 Bin フォルダーまたは Global Assembly キャッシュ内のプリコンパイル済みアセンブリに移動することです。 この修正プログラムはパフォーマンスに対応しませんが、すべてのコンピューターでアセンブリの名前が同じであることを保証します。

注意

複雑なデータ型を viewstate に格納し、この問題が発生した場合、呼び出し履歴情報には次のスタックが含まれます。

[FileNotFoundException: Could not load file or assembly 'App_Web_fx--sar9, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.]
 System.RuntimeTypeHandle._GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, Boolean loadTypeFromPartialName) +0
System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark) +72
System.RuntimeType.PrivateGetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark) +58
System.Type.GetType(String typeName, Boolean throwOnError) +57
System.Web.UI.ObjectStateFormatter.DeserializeType(SerializerBinaryReader reader) +192 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +943 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +384 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +198 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +210 
System.Web.UI.ObjectStateFormatter.DeserializeValue(SerializerBinaryReader reader) +198 
System.Web.UI.ObjectStateFormatter.Deserialize(Stream inputStream) +142

viewstate マシン認証コード (MAC) 機能の目的は、悪意のある viewstate を含む要求をクライアントが送信できないことです。 既定では、この機能は、 Machine.config ファイルの次のフラグで有効になっています。

enableViewStateMac="true"

対処している問題が MAC 機能に関連しているかどうかを判断する最も簡単な方法は、機能をオフにすることです。 この機能をオフにするには、 Machine.config ファイルのフラグを次のコードに変更します。

enableViewStateMac="false"

viewstate エラーが表示されなくなった場合、問題は MAC 機能に関連しています。

重要

問題の診断に役立つ viewstate MAC 機能のみをオフにします。 問題を回避するには、viewstate MAC をオフのままにしないでください。 その場合は、セキュリティ ホールを導入できます。 詳細については、「 セキュリティで保護された ASP.NET アプリケーションの構築: 認証、承認、およびセキュリティで保護された通信を参照してください。

ビューステート MAC 機能をオフにし、HTML エンコードされていないコントロール (ラベル コントロールなど) に viewstate を使用すると、攻撃者はビューステート データを改ざんし、任意のデータを viewstate に配置できます。 この任意のデータはデコードされ、ポストされたページをレンダリングするときにコントロールによって使用されます。 その結果、攻撃を防ぐために作業しない限り、攻撃者はスクリプトをアプリケーションに挿入できます。 たとえば、攻撃者はデータをデコードし、Label コントロールがあるデータにスクリプトを挿入し、Web サイトからリンクすることができます。 リンクを選択したユーザーは、認証 Cookie またはセッション ID を盗む可能性があるスクリプトインジェクション攻撃の被害者になります。 また、このスクリプトを使用すると、ビューステートを使用するコントロールの状態データを攻撃者が変更でき、結果としてアプリケーション固有の攻撃が発生する可能性があります。

一般に、Microsoft は、出力をエンコードしていないすべてのコントロール (例えば、DataGrid コントロール、DataList コントロール、Label コントロール、および他のコントロール) に対してビュー ステートを無効にしているか、または各要求で常にその値を安全であると知られているものに明示的に設定しているという自信がない限り、ビュー ステート MAC 機能をオフにしないことをお勧めします。

エラー メッセージが表示されたときに発生する例外を正確に判別する

残念ながら、この記事の 「概要 」セクションにある無効な viewstate エラー メッセージは有益ではありません。 エラー メッセージは、viewstate の処理中に例外が生成されたことが原因で発生します。 問題は、例外が使用され、その詳細がエラー メッセージで失われることです。

デバッガーを使用すると、元の例外を判別できます。 これを行うには、デバッガーを ASP.NET プロセス (Aspnet_wp.exe または W3wp.exe) にアタッチし、すべての例外をキャッチするように設定する必要があります。 デバッガーは関係のないいくつかの例外で停止する可能性がありますが、最終的には viewstate 例外にヒットし、トラブルシューティングに役立つ情報を提供します。

次の手順は、ランタイム デバッガー (Cordbg.exe) を使用する例です。

  1. コマンド プロンプトで、 iisreset コマンドを実行して、適切な開始点が提供されていることを確認し、サイト上のページを参照します。

  2. cordbg.exe を実行します。

  3. <pro>」と入力し、 ENTER キーを押します。 マネージド プロセスの一覧が表示されます。 Aspnet_wp.exeまたはW3wp.exeプロセスが表示されます。 PID を書き留めます。

  4. <PID>を入力します。

    メモ

    PID手順 3 で示した PID に置き換えます。

  5. ca e を入力して、すべての例外を中断するようにCordbg.exeに指示し、「プロセスを実行<gto>」と入力します。

  6. 例外が発生するたびに、「 <w> 」と入力してスタックを表示します。 スタックがビューステート例外である場合 (スタック上の LoadPageStateFromPersistenceMedium を探します)、すべての例外とスタック情報をコマンド ウィンドウからコピーし、情報を保存します。 この情報は、問題を理解するのに役立ちます。 例外が関連しない場合は、「 <g>」と入力します。

セッションに viewstate を格納してみてください

既定では、viewstate はラウンドトリップされ、ブラウザーに送信される <input type=hidden> フィールドが含まれます。 その後、ブラウザーは次の要求でこのフィールドをサーバーに送り返します。 場合によっては、このビューステートが大きくなり、問題の原因になる可能性があります。 一部のブラウザーでは、このような大きな非表示フィールド(およびそれに伴う大きな要求)を処理できず、その結果、ビューステートが切り捨てられることがあります。 viewstate を切り捨てると、"viewstate corrupted" というエラー メッセージが表示されます。 この動作は、より単純なブラウザーで発生する可能性が高くなります。 たとえば、この動作は PDA 上のブラウザーで発生する可能性があります。

このような問題が発生している可能性があるかどうかを判断するには、viewstate をセッションに格納してみてください。 この方法を次の例に示します。

<%@ language=c# debug=true %> 

<script runat=server> 
protected override object LoadPageStateFromPersistenceMedium() 
{ 
    return Session["_ViewState"]; 
}

protected override void SavePageStateToPersistenceMedium(object viewState) 
{ 
    Session["_ViewState"] = viewState; 
}

void TextChanged(object o, EventArgs e) 
{ 
    Response.Write("TextChanged"); 
} 
</script> 
<form runat=server> 
<asp:button text=Test runat=server/> 
<asp:textbox ontextchanged=TextChanged runat=server/> 
<input type=hidden name=__VIEWSTATE> 
</form> 

ワーカー プロセスのリサイクルによって問題が発生するかどうかを判断する

次のシナリオについて考えてみます。

  • Microsoft インターネット インフォメーション サービス (IIS) 6.0 で ASP.NET を実行しています。
  • アプリケーション プールは、ローカル システム アカウント、ネットワーク サービス アカウント、または管理レベルのアカウント以外の ID で実行されています。
  • validationKey要素の<machineKey>属性は、構成ファイルでAutoGenerateに設定されます。

このシナリオでは、次の手順を実行すると、viewstate エラーが発生します。

  1. ユーザーがページを参照します。
  2. ASP.NET アプリケーションをホストするワーカー プロセスがリサイクルします。
  3. ユーザーがページをポストバックします。

このシナリオの回避策として、構成ファイルで明示的な validationKey 属性を使用します。

関連情報