none
ASP.NET で ViewState に DataTable を渡すと件数が多い場合エラーになる RRS feed

  • 質問

  • ASP.NET、C# でプログラムの開発をしています。

    データベースの検索結果一覧を DataTable に格納し、
    プログラムで ViewState に DataTable を渡しています。
    検索結果の表示には ListView を使用しております。

    DataTable 型を渡す理由は、検索結果一覧を編集する時に
    DataTable の書き換えと、データベースの書き換えを行うためです。

    コードサンプル

    SqlDataAdapter adapter = new SqlDataAdapter();
    adapter.SelectCommand = new SqlCommand(strSql, con);
    adapter.Fill(dtRec);

    // ここでデータテーブルを ViewState に格納
    ViewState["dtRec"] = dtRec;

    // 画面表示
    ListViewRec.DataSource = dtRec;
    ListViewRec.DataBind();

    ※dtRec が DataTable 型、ListViewRec が LivtView です。

    プログラム中ではエラーが発生しないものの、
    DataTable に格納する件数が多くなると(1万件以上になった場合あたり)
    画面描画時に以下のようなエラーが発生します。

    Microsoft JScript 実行時エラー:
    Sys.WebForms.PageRequestManagerServerErrorException:型
    'System.Data.DataTable' の値 'dtRec' のシリアル化中にエラーが発生しました。

    なお DataTable を渡さない場合には上記エラーが発生しない事を確認しております。

    件数が少ない場合発生しないため、設定か仕様なのかなと考えておりますが
    アドバイスをいただけませんでしょうか?

    2010年9月22日 1:51

回答

  • ViewStateに大量データを入れると、Webサーバー-Webブラウザ間で受け渡しされるため、画面描画が遅くなったり動作が遅くなったりします。

    ASP.NET ビューステートの概要 より

    ビューステート情報は XML にシリアル化された後で Base64 エンコーディングを使用してエンコードされます。このため、大量のデータが生成される可能性があります。ページをサーバーにポストすると、ビューステートの内容がページのポストバック情報の一部として送信されます。ビューステートに大量の情報が格納されている場合、ページのパフォーマンスに影響を与える可能性があります。アプリケーションの通常のデータを使用してページのパフォーマンスをテストし、ビューステートのサイズがパフォーマンス上の問題を発生させるかどうかを確認します。

    別の設計を考えることをおすすめします。

    • 回答としてマーク 山本春海 2010年10月4日 6:53
    2010年9月22日 2:55
  • そもそもViewStateは画面に表示されるデータを一時的に保存しておくのを目的としており、画面に表示されていないデータまで保存しておくべきではありません。今回の対策として安易な方法としてはSessionオブジェクトに保存するように変更することですが、InProcモードで動いているとセッション情報がいつ失われるかわかりませんので、InProcモード以外で動かすことを検討してみて下さい。
    しかし、一番良い解決方法は前述したようにカスタムページングです。ただ、ちょっと改修」量が多くなるかもしれません。

    ASP.NET 2.0とSQL Server 2005によるカスタムのページング処理
    http://japan.internet.com/developer/20060620/25.html

    あとはちょっとしたテクニックでViewSateの情報をサーバー側に持つ方法です。今回の件の対応としては有効かもしれません。以下を参考にしてみて下さい。

    GridViewでどこかの行をクリックしたときに全ての行を編集状態にしたい
    http://social.msdn.microsoft.com/Forums/ja-JP/vbgeneralja/thread/5dd7d9e7-498b-4a34-a95c-f9797fde09f7

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2010年9月22日 4:58
    モデレータ
  • ViewSateが長すぎてどこかで欠落しているのが原因でしょう。web.configに<httpRuntime maxRequestLength = 大きなサイズを指定 />を追加すれば解決できるかもしれませんが、大量のトラフィックが流れるためお勧めできません。ちなみにmaxRequestLengthのデフォルト値は約4Mバイトです。
    そもそも大量の検索結果を一度に見せられてもユーザーは困惑するのではないでしょうか? 検索結果がたくさんヒットするようであればページングして分割すべきです。その場合もカスタムページングを行えば、そのページのみのデータをデータベースから取得して表示しますので効率的です。

    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    • 回答としてマーク 山本春海 2010年10月4日 6:54
    2010年9月22日 3:11
    モデレータ
  • >逆になってしまいますが、画面に表示されている ListView のデータを取得し、
    >再度 DataTable に変換するというような事は可能なのでしょうか?

    そういう事をしないで、リクエストの度にデータベースから同じ条件で SELECT したらいいのではないでしょうか。
    本来なら、表示する数件分 SELECT すべきでしょうけど。
    • 回答としてマーク 山本春海 2010年10月4日 6:54
    2010年9月22日 6:11

すべての返信

  • ViewStateに大量データを入れると、Webサーバー-Webブラウザ間で受け渡しされるため、画面描画が遅くなったり動作が遅くなったりします。

    ASP.NET ビューステートの概要 より

    ビューステート情報は XML にシリアル化された後で Base64 エンコーディングを使用してエンコードされます。このため、大量のデータが生成される可能性があります。ページをサーバーにポストすると、ビューステートの内容がページのポストバック情報の一部として送信されます。ビューステートに大量の情報が格納されている場合、ページのパフォーマンスに影響を与える可能性があります。アプリケーションの通常のデータを使用してページのパフォーマンスをテストし、ビューステートのサイズがパフォーマンス上の問題を発生させるかどうかを確認します。

    別の設計を考えることをおすすめします。

    • 回答としてマーク 山本春海 2010年10月4日 6:53
    2010年9月22日 2:55
  • DataTable に格納する件数が多くなると(1万件以上になった場合あたり)


    エラーがでなくても運用始まったら速度的に問題になりそうな。

    # VSのASP.NETテストサーバーでテスト実行している分にはオンメモリなので意識しなくてもいいのでしょうけれど。

    それにListViewの表示を保持するためにListViewに設定されたデータがViewStateに入っている(はず、あらためては未確認)のにDataTableも入れる必要あるのでしょうか。

     

     


    http://blogs.wankuma.com/hatsune/
    2010年9月22日 3:04
  • ViewSateが長すぎてどこかで欠落しているのが原因でしょう。web.configに<httpRuntime maxRequestLength = 大きなサイズを指定 />を追加すれば解決できるかもしれませんが、大量のトラフィックが流れるためお勧めできません。ちなみにmaxRequestLengthのデフォルト値は約4Mバイトです。
    そもそも大量の検索結果を一度に見せられてもユーザーは困惑するのではないでしょうか? 検索結果がたくさんヒットするようであればページングして分割すべきです。その場合もカスタムページングを行えば、そのページのみのデータをデータベースから取得して表示しますので効率的です。

    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    • 回答としてマーク 山本春海 2010年10月4日 6:54
    2010年9月22日 3:11
    モデレータ
  • みなさま回答ありがとうございます。

    実は退職してしまった前任者が作ったプログラムを修正している状態でして引き継いで修正をしています。
    ある程度作りこまれてしまっている状態ですので完全修正は難しくなってしまっています・・。

    ViewState の使用が不適切だという事はわかりました。
    現時点で ViewState でページング処理は行われており、一度に表示されるデータは数件程度です。

    逆になってしまいますが、画面に表示されている ListView のデータを取得し、
    再度 DataTable に変換するというような事は可能なのでしょうか?
    これができれば修正は最小限で済むと考えていますが、
    検索しても見つからないので一般的ではないのでしょうか?

    もしくはまったく別のコントロールを使用し再設計を行った方がよろしいのでしょうか?
    度々申し訳ありませんが、よろしくお願いします。

    2010年9月22日 4:42
  • そもそもViewStateは画面に表示されるデータを一時的に保存しておくのを目的としており、画面に表示されていないデータまで保存しておくべきではありません。今回の対策として安易な方法としてはSessionオブジェクトに保存するように変更することですが、InProcモードで動いているとセッション情報がいつ失われるかわかりませんので、InProcモード以外で動かすことを検討してみて下さい。
    しかし、一番良い解決方法は前述したようにカスタムページングです。ただ、ちょっと改修」量が多くなるかもしれません。

    ASP.NET 2.0とSQL Server 2005によるカスタムのページング処理
    http://japan.internet.com/developer/20060620/25.html

    あとはちょっとしたテクニックでViewSateの情報をサーバー側に持つ方法です。今回の件の対応としては有効かもしれません。以下を参考にしてみて下さい。

    GridViewでどこかの行をクリックしたときに全ての行を編集状態にしたい
    http://social.msdn.microsoft.com/Forums/ja-JP/vbgeneralja/thread/5dd7d9e7-498b-4a34-a95c-f9797fde09f7

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2010年9月22日 4:58
    モデレータ
  • >逆になってしまいますが、画面に表示されている ListView のデータを取得し、
    >再度 DataTable に変換するというような事は可能なのでしょうか?

    そういう事をしないで、リクエストの度にデータベースから同じ条件で SELECT したらいいのではないでしょうか。
    本来なら、表示する数件分 SELECT すべきでしょうけど。
    • 回答としてマーク 山本春海 2010年10月4日 6:54
    2010年9月22日 6:11
  • 詳細な解説ありがとうございました。

    ViewState と Session が同様なものと勝手に思い込んでいました。
    ViewState はエンコードしてページ内に記述されていたのですね・・。

    今回は時間が無いため、暫定的に Session で逃げる事にしました。
    (サーバーサイド ViewState がうまくできませんでした。)

    カスタムページングとサーバーサイド ViewState については
    パフォーマンスアップになりそうですので、もう少し余裕のあるときに試したいと思います。

    今まで触ったことのない ASP.NET を無理矢理引き継いでいるので
    「とりあえず動く」のを優先しております・・。
    本来であればもっと勉強し、質問するべきだとは思いますがお恥ずかしい限りです。

    みなさんありがとうございました。

    2010年9月22日 6:33