DOBON.NET DOBON.NETプログラミング掲示板過去ログ

「無効なポストバックまたはコールバック引数です」について

環境/言語:[Windows Vista/7 C# VC2010 Webアプリ]
分類:[ASP.NET]

お世話になっております。

今まで、動作していた(開発中ですが)Webアプリがある時から下記のエラーでて動かなくなりました。

エラー全文
「無効なポストバックまたはコールバック引数です。イベントの検証は、構成の <pages enableEventValidation="true"/>、またはページの <%@ Page EnableEventValidation="true" %> を使用して有効にされます。セキュリティの目的により、この機能は、イベントをポストバックまたはコールバックする引数が、それらを最初に表示したサーバー コントロールから発行されていることを確認します。データが有効であり、予期されている場合、検証のためのポストバックまたはコールバック データを登録するために ClientScriptManager.RegisterForEventValidation メソッドを使用してください。」

このため、マスターページ使用の子に  enableEventValidation="false" を追加して
<%@ Page Title="ホーム ページ" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" enableEventValidation="false" CodeBehind="Default.aspx.cs" Inherits="ReportForm._Default" %>


実行してみましたが、見掛け上、ポストバックしていますが、変化ありません。
期待の動作として、GridView内のボタンをしたら別ページを呼び出す(別ウインドウで)単純なもの。

下記にそのコードです。
GridView 内の項目のチェックボックスをテンプレートフィールドにして
<asp:TemplateField HeaderText="履歴" SortExpression="KanjaHistory">
<EditItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server"
Checked='<%# Bind("KanjaHistory") %>' />
</EditItemTemplate>
<ItemTemplate>
<asp:Button ID="Button1" runat="server" CausesValidation="False" Text="表示"
CommandName="KanjaHistory" CommandArgument="<%# ((GridViewRow) Container).RowIndex%>"
      Visible='<%# (bool)Eval("KanjaHistory") %>' />
</ItemTemplate>
</asp:TemplateField>

で、サーバ側の処理....ですが、実際下記が呼び出される前にエラーが出るのでクライアント側の問題だと思う。
// 履歴ボタンを押した(テンプレートに追加したボタンは、下記で処理する)
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "KanjaHistory")
{
// Retrieve the row index stored in the
// CommandArgument property.
int index = Convert.ToInt32(e.CommandArgument);

// Retrieve the row that contains the button
// from the Rows collection.
GridViewRow row = GridView1.Rows[index];
:
:


ググってみると、enableEventValidation="false" この文を追加すればセキュリティは甘くなるけど解決するとのことが書いてありますが、私のアプリでは、動きません。
なぜこうなったかを考えて見ましたが、思い当たる節はGridViewの「データソースの構成」を行った後、表示される「’GridView1’のフィールドとキーを最新の情報に更新します。......」
で、「いいえ」を押したぐらい。その後、上記のため、やり直して「はい」にしたけど変わらず。

以上、長文で申し訳ありませんが。ご教示ください。
■No29391に返信(Hiroさんの記事)

> 「無効なポストバックまたはコールバック引数です。イベントの検証は、構成

Google検索して適当に出てきたページです。
http://tatumin.blog66.fc2.com/blog-entry-288.html
■No29392に返信(shuさんの記事)
> ■No29391に返信(Hiroさんの記事)
>
>>「無効なポストバックまたはコールバック引数です。イベントの検証は、構成
>
> Google検索して適当に出てきたページです。
> http://tatumin.blog66.fc2.com/blog-entry-288.html

お世話になります。
ページを見ましたが、よく意味がわかりません。
「Webコントロール以外のボタンのID属性を削ればOK」
とありますが、Webコントロール以外のボタン....つまりrunat="server"でなくてhtmlのボタンのこと?
これなら、このページ内で使用していません。

さらに、
「ASPが認識しているそのページ」と、
「実際のSubmitデータ」の差分。
と書かれている部分ですが、どういった風に考えればいいのでしょか?
2011/11/26(Sat) 13:04:15 編集(投稿者)

■No29393に返信(Hiroさんの記事)
テキストボックスの値やドロップダウンリストでどれが選択されているか、
チェックボックスリストでどれが選択されているかなどは、クライアント側で変更さ
れることが予測されます。一方テキストボックスのname属性やドロップダウンリスト
の項目そのもの、チェックボックスリストの項目そのものなどは、クライアント側で
変更されないはずで、変更されないことが期待されます。変更されるべきでないもの
が変更されてクライアントからサーバーに送られたばあいに、サーバー側でのイベン
トが発生する前の段階で、情報の不整合を検出して、処理を中断する仕組みがありま
す。それが無効なポストバックまたはコールバック引数です、という例外と関わりが
あります。

クライアント --> サーバー
ページを表示するときに1回目のリクエストがクライアントからサーバーに送られま
す。

クライアント <-- サーバー
それに対応するレスポンスがサーバーからクライアントに送られてページがブラウザ
に表示されます。このときにサーバーからクライアントに送られるレスポンスに変更
されるべきでないコントロールの情報が含まれます。

クライアント --> サーバー
ページがサブミットされると、2回目のリクエストがクライアントからサーバーに送
られます。このときに1回目のレスポンスで送られてきた変更されるべきでない
コントロールの情報もサーバーに送られます。1回目のレスポンスでサーバーからク
ライアントに送られた、変更されるべきでないコントロールの情報と、サブミットさ
れてきたコントロールの情報が整合するか、サーバー側で確認されます。整合すれば
サーバー側でのイベントが発生します。不整合であれば件の例外が発生します。

変更されるべきでないコントロールの情報はinput type="hidden"の隠し項目として
ページに含まれます。name属性は__EVENTVALIDATIONです。ブラウザでソースを表示
すれば見ることができます。

__EVENTVALIDATIONに格納される、変更されるべきでないコントロールの情報は
サーバー側でコントロールの情報はこれだ、ということで認識されたもの、
「ASPが認識しているそのページ」のことです。2回目以降のリクエストでサブミット
されるコントロールの情報は「実際のSubmitデータ」のことです。2つの情報が整合
するか否かは差分のことです。

例外が発生する原因としては、__EVENTVALIDATIONのname属性をもつ隠し項目が
ページに配置される前に2回目のリクエストが送られた、クライアント側で
JavaScriptを使ってサーバーコントロールが変えられた、といったことが考え
られます。例外発生時のスタックトレースにはどのように出力されていますか?

ポストバックするけれども変化がないというのは、例外が出ることに変化が無いとい
うことですか?それとも、例外は出なくなるけれども、期待する動作が行われないと
いうことですか?例外は出なくなるけれども期待する動作が行われない、ということ
であれば、GridView.RowCommandイベントのハンドラであるGridView1_RowCommand
メソッドにブレークポイントを仕掛けて処理に入るかどうかを確認して、もし処理に
入らなければ、イベントとイベントハンドラが関連付けられているか確認してみてく
ださい。
■No29394に返信(もりおさんの記事)
> 2011/11/26(Sat) 13:04:15 編集(投稿者)
>
> ■No29393に返信(Hiroさんの記事)
> 変更されるべきでないものが変更されてクライアントからサーバーに送られたばあいに...
という意味は、分かりました。悪意を持った改ざんなどの対応策のひとつでしょう

> ポストバックするけれども変化がないというのは、
ポストバックが起きますが、画面上(ページ上)変化がありません。IE上のタブは、更新(?ウエイト様の変化してすぐ戻る。ページに変化なし)
また、GridView.RowCommandイベントのハンドラにブレークポイントを貼ってますが呼び出される前にエラーが表示されます。

> 入らなければ、イベントとイベントハンドラが関連付けられているか確認
OKです。同時に、
onselectedindexchanged="GridView1_SelectedIndexChanged"がありますが、こちらは問題なく呼ばれます。
■No29395に返信(Hiroさんの記事)
ページに変化が無いということと、エラーが表示されるということがつながらないよ
うに思えるのですが、「無効なポストバックまたはコールバック引数です」という例
外が投げられたときには、当該例外が発生したというページに遷移するはずだと思い
ますが、その遷移はないということですか?

ちょっと状況を整理させていただきたいのですが、GridViewのボタンを押下すると、
「無効なポストバックまたはコールバック引数です」という例外が発生する。それを
回避するために、ページディレクティブにEnableEventValidation="False"を追加す
る。そして、GridViewのボタンを押下すると、ページに変化は無く、エラーが表示さ
れる。ということですよね。

EnableEventValidation="False"をページディレクティブに追加して、GridViewのボ
タンを押下して、GridView.RowCommandイベントのハンドラが呼ばれる前に発生する
エラーというのは、「無効なポストバックまたはコールバック引数です」という例外
と同一のものですか?

GridViewに選択ボタンがあって、GridView.SelectedIndexChangedイベントとそのハ
ンドラが関連付けられているということですか。選択ボタンを押下して、問題なく呼
ばれるというのはGridView.SelectedIndexChangedイベントのハンドラが問題なく呼
ばれるということですか?それともGridView.RowCommandイベントのハンドラが問題
なく呼ばれるということですか?選択ボタンを押下したときには両方のイベントが発
生すると思いますが、両方のハンドラは問題なく呼ばれますか?
■No29396に返信(もりおさんの記事)
> ■No29395に返信(Hiroさんの記事)
> 当該例外が発生したというページに遷移するはずだと思いますが、その遷移はないということですか?
EnableEventValidation="true"の時はエラーを表示するページに遷移します。


> 回避するために、ページディレクティブにEnableEventValidation="False"を追加す
> る。そして、GridViewのボタンを押下すると、ページに変化は無く、エラーが表示さ
> れる。ということですよね。
はい、ページに変化ありません。そしてエラーも出ません。なのでGridView.RowCommandイベントのハンドラも呼ばれません。つまり何も起きていません。
GridView.RowCommandが呼ばれればいいのですが…

>
> EnableEventValidation="False"をページディレクティブに追加して、GridViewのボ
> タンを押下して、GridView.RowCommandイベントのハンドラが呼ばれる前に発生する
> エラーというのは、「無効なポストバックまたはコールバック引数です」という例外
> と同一のものですか?
そうです。最初にグダグダ書いた長文のエラーです。


> GridViewに選択ボタンがあって、GridView.SelectedIndexChangedイベントとそのハ
> ンドラが関連付けられているということですか。選択ボタンを押下して、問題なく呼
> ばれるというのはGridView.SelectedIndexChangedイベントのハンドラが問題なく呼
> ばれるということですか?それともGridView.RowCommandイベントのハンドラが問題
> なく呼ばれるということですか?選択ボタンを押下したときには両方のイベントが発
> 生すると思いますが、両方のハンドラは問題なく呼ばれますか?
両方呼び出されます。選択ボタンは、正常に呼び出されるのに<ItemTemplate>ととして追加したボタンがエラーになるのでとりあえず書いてみました。
推測するに、GridViewそのものは正常?と思いますが、追加したボタンでこのエラーが起きることがよくわかりません。

先に説明いただいた、整合性に関しては理解したつもりです。

よろしくお願いします。
■No29397に返信(Hiroさんの記事)
えっと、エラーが発生するのかしないのかよくわからなくなってきました。
EnableEventValidation="False"をページディレクティブに追加するとエラーは発生
せず、追加しなければ発生するということでよいですよね。

EnableEventValidation="False"はイベントの検証を行わないというものであり、
イベントを発生させないというものではありませんで、エラーが出ないことに
よってイベントハンドラが呼ばれないわけではないでしょうから、なのでという接続
は違うと思いますが、イベントとイベントハンドラが関連付けられていて、イベント
ハンドラが呼ばれないということは、イベントハンドラの関連付けられたオブジェク
トが、別のオブジェクトに置き換えられている可能性があるということですかね。
Page.Loadイベントで無条件にGridView.DataBindメソッドを呼んで、
GridView.RowCreatedイベントが2回発生するようにしたところ、類似した現象を確認
できました。記述されているコードを丸ごと教えてもらえないでしょうか。
■No29398に返信(もりおさんの記事)
> ■No29397に返信(Hiroさんの記事)
> Page.Loadイベントで無条件にGridView.DataBindメソッドを呼んで、
> GridView.RowCreatedイベントが2回発生するようにしたところ、類似した現象を確認
> できました。記述されているコードを丸ごと教えてもらえないでしょうか。
ここに書かれているように私のコードもポストバック後にデータの更新を再表示するためにGridView.DataBindをしていました。これをコメントにすると当該エラーは出なくなりました。

しかし、GridViewに最新の状態を反映したいためポストバックの度に内容を更新したいのですがどこに書いたらいいですか?
っていうか、ここでGridView.DataBindするとこんな苦労するエラーになるのですか?


内容更新とは、テキストボックスがあり、これにデータを入れて別にある更新ボタンを押すとポストバックしGridViewに登録済みのフラグ(bool)を表示させています。いくつかあるデータの中で処理済みかどうか知らせるため。

コードが必要な場合、アップしますが、aspxとaspx.cs合わせて1000行ほどです。
■No29399に返信(Hiroさんの記事)

> しかし、GridViewに最新の状態を反映したいためポストバックの度に内容を更新したいのですがどこに書いたらいいですか?
> っていうか、ここでGridView.DataBindするとこんな苦労するエラーになるのですか?
大変失礼しました、Page_LoadにGridView.DataBindを書かなくてもGridViewのデータは更新されていました。

お騒がしました。でも、Page_LoadにGridView.DataBindを書くといけないんですね。
解決済み!
■No29400に返信(Hiroさんの記事)
コードを教えてほしいと言いましたのは、興味深い現象でしたので、Hiroさんのコー
ドでの現象が発生する条件を知りたいためのものでした。解決されたようでなりより
です。SqlDataSourceなどのDataSourceコントロールがGridViewコントロールと
DataSourceIDプロパティによって関連付けられているばあいには、DataSourceコント
ロールがDataBindメソッドを自動的に呼びますので、コードを記述してDataBindメ
ソッドを呼ぶ必要は基本的にはありません。

DataSourceコントロールを使用せず、DataBindメソッドを呼ぶ必要があるばあいには、
ポストバックのときのイベントの順番を考慮する必要があります。

Page.Load
GridView.RowCommand
Page.PreRender
GridView.PreRender

イベントは上記のような順番で発生します。Page.Loadイベントのあとに、ページの
ボタン押下などにともなうGridViewなどのコントロール変更イベント発生し、そのあ
とにPreRenderイベントが発生します。コントロール変更イベントが発生するときに
イベントの検証が行われますので、コントロール変更イベントが発生したあと、
PreRenderイベントのタイミングでDataBindメソッドを呼ぶのが適切だと思われます。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板