none
Sessionの動作について RRS feed

  • 質問

  • みなさん、こんにちは。

    Sessionの動作について疑問があります。

    開発環境:
    Visual Studio2008

    対象とするFramework:
    .NET Framework2.0


    protected void Page_Load(object sender, EventArgs e)   
    {
        if (IsPostBack)
        {
            dTable =(DataTable)Session["dt"];
        }
        else{
            using (conn = new SqlConnection(strConnection))
            {               
                dTable = new DataTable();
                adapter = new SqlDataAdapter(query, conn);
                adapter.Fill(dTable);
                Session.Add("dt", dTable);
            }
        }
    }
    protected void btnWrite_Click(object sender, EventArgs e)
    {
        DataRow row= dTable.NewRow();
        row[1] = DateTime.Now.ToShortDateString();
        row[2] = "testString:"+DateTime.Now.ToString();       
        dTable.Rows.Add(row);
    }

    上記のようなコードがあります。書き込みボタン(btnWrite)を
    押下すると、dTableに行を保存します。
    しかし、ここで疑問なのですが開発環境だとbtnWrite_Clickに
    Session.Add("dt", dTable);を追加しなくても書き込んだ内容を
    DataTableインスタンスが保持しているということです。
    例えば当該ボタンを3回押せば3行dTableが行を保持しています。

    これって仕様なのでしょうか?

    不思議に思い試しにint型で値を保持するか調べたのですが
    保持されませんでした。

    そこで、もうひとひねりして参照型だと保持するのかと
    クラスを作成してそれを変更したところ保持することが
    わかりました。

    int型と試しに作成したクラスは共にPage_LoadのUsing内で
    値を初期化してSessionに保存して、btnWrite_Click内で
    値を追加しています。

     あまりに初歩的な質問で恥ずかしいのですが、恥を
    忍んで質問をします。

     みなさん、よろしくお願いします。

    2009年12月3日 4:07

回答

  • ・まず1つ目
     Sessionは、リクエストを跨いで値の受け渡しを行うためのものです。
    ・そして2つ目
     参照型と値型の違いは、理解されていますか?

    この2つをしっかり理解していれば、わかると思います。
    Sessionとかを切り離して以下のコードでどうなるかを考えてみてください。

    // データの準備
    DataTable dt = (DBなどから取得);
    int i = 0;
    
    // sessionに保持するということを、別変数にコピーに変えてみる。
    DataTable sessionDt = dt;
    int sessionI = i;
    
    // sessionから値を復元する
    DataTable dt2 = sessionDt;
    int i2 = sessionI;
    
    // sessionから取得したものを編集
    dt2.Rows.Add(何か行を追加);
    i2 = 300;
    
    // この時点でdtとiがどうなっているか確認する
    恐らくdtの方は、行が追加されていて、iの方は、0のままだと思います。
    これと同じようなことがおきています。

    どうでしょう?これで、わからないところとかがあったら、また質問ください。

    かずき Blog:http://blogs.wankuma.com/kazuki/
    2009年12月3日 9:48
  • セッション変数を外部サーバに記憶するようにしていてもそうなので、セッション上のデータは新規かどうか関係なくすべてが保存の対象になっているのでしょうね(これは、a_かずき_さんのおっしゃる参照型の性質はあまり関係なく、単にASP.NETの仕様の問題になります)。
    外部サーバーにセッション変数を記憶する場合でも、明示的に書き戻さなくても保存されるのは参照型だけなんでしょうか? であれば、参照型が関係しているのだと思います。
    セッション変数が値型のオブジェクトを保持しており、そのオブジェクトを取り出す時には、そのオブジェクトのコピーを受け取ります。コピーをいくら操作してもセッション変数にある元々の値型のオブジェクトは変わりません。したがって、書き戻さなければセッション変数内の値型のオブジェクトは変わりません。
    セッション変数が参照型のオブジェクト(実際にはオブジェクトへの参照)を保持している場合には、そのオブジェクトの参照を受け取ります。セッション変数が保持している参照も、セッション変数から今取り出した参照も同じオブジェクトを指しています。したがって、セッション変数から今取り出したオブジェクトを操作しても、書き戻す必要が無いのでしょう。
    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    2009年12月4日 1:45
    モデレータ
  • セッション状態モードがSQLServerとStateServerの場合はシリアライズされるようです。

    セッション状態モード
    http://msdn.microsoft.com/ja-jp/library/ms178586(VS.80).aspx


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    2009年12月4日 6:46
    モデレータ

すべての返信

  • ・まず1つ目
     Sessionは、リクエストを跨いで値の受け渡しを行うためのものです。
    ・そして2つ目
     参照型と値型の違いは、理解されていますか?

    この2つをしっかり理解していれば、わかると思います。
    Sessionとかを切り離して以下のコードでどうなるかを考えてみてください。

    // データの準備
    DataTable dt = (DBなどから取得);
    int i = 0;
    
    // sessionに保持するということを、別変数にコピーに変えてみる。
    DataTable sessionDt = dt;
    int sessionI = i;
    
    // sessionから値を復元する
    DataTable dt2 = sessionDt;
    int i2 = sessionI;
    
    // sessionから取得したものを編集
    dt2.Rows.Add(何か行を追加);
    i2 = 300;
    
    // この時点でdtとiがどうなっているか確認する
    恐らくdtの方は、行が追加されていて、iの方は、0のままだと思います。
    これと同じようなことがおきています。

    どうでしょう?これで、わからないところとかがあったら、また質問ください。

    かずき Blog:http://blogs.wankuma.com/kazuki/
    2009年12月3日 9:48
  • 検証なさっている通り、セッションから取り出した参照型のデータを変更した場合、明示的に書き戻し動作をしなくてもその変更は保存されます。

    ASP.NET状態サービスといって外部のサーバにセッション変数を保存するサービスを利用していてもそうなので、セッションは新規登録されたものだけを保存するのではなく、辞書内に存在するすべてのデータを毎回保存しているのでしょうね。実際私も、この性質があるのでセッションから取り出したデータの書き戻しは日頃していません。

    ただ、msdnのリファレンスにはひとことも「書き戻し動作は必要ない」とは書かれていないのです。
    (私が見落としているだけかもしれませんが)

    ということは、書き戻しをしなくても変更が保存されるのはあくまで「今の実装の気まぐれ」であって、今後は書き戻しなしには変更が保存されない実装のセッションシステムが標準になったりするかもしれないということです。

    というわけで、書き戻しをしないというやり方は本来危険な使い方なのかもしれません。この辺、もう少し詳しい方のフォローがほしいです。
    2009年12月4日 1:19
  • セッション変数を外部サーバに記憶するようにしていてもそうなので、セッション上のデータは新規かどうか関係なくすべてが保存の対象になっているのでしょうね(これは、a_かずき_さんのおっしゃる参照型の性質はあまり関係なく、単にASP.NETの仕様の問題になります)。
    外部サーバーにセッション変数を記憶する場合でも、明示的に書き戻さなくても保存されるのは参照型だけなんでしょうか? であれば、参照型が関係しているのだと思います。
    セッション変数が値型のオブジェクトを保持しており、そのオブジェクトを取り出す時には、そのオブジェクトのコピーを受け取ります。コピーをいくら操作してもセッション変数にある元々の値型のオブジェクトは変わりません。したがって、書き戻さなければセッション変数内の値型のオブジェクトは変わりません。
    セッション変数が参照型のオブジェクト(実際にはオブジェクトへの参照)を保持している場合には、そのオブジェクトの参照を受け取ります。セッション変数が保持している参照も、セッション変数から今取り出した参照も同じオブジェクトを指しています。したがって、セッション変数から今取り出したオブジェクトを操作しても、書き戻す必要が無いのでしょう。
    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    2009年12月4日 1:45
    モデレータ
  •  a_かずき_さん、miuras_net、trapemiyaさん回答して下さりありがとうございます。
     
    a_かずき_さんの提示して下さったコードとtrapemiyaさんの文章を読んで、もしかした
    らそういうことなのかと頭の中でもうひと押しあれば理解できそうな事を理解すること
    ができました。

    ありがとうございました。

    miuras_netさんの下の意見については俺もこのように考えていました。

    ”msdnのリファレンスにはひとことも「書き戻し動作は必要ない」とは書かれていないのです。”

    しかし、a_かずき_さんやtrapemiyaさんの意見を考えると参照型については当然の事な
    のでわざわざリファレンスに書くことも無いということで書いてないような気がしてき
    ました。

    ”セッションは新規登録されたものだけを保存するのではなく、辞書内に存在するすべてのデータを毎回保存しているのでしょうね。”

      また、上記についてはAddメソッドをコールした時だけシリアル化しているわけでは
    ないのですね。大変勉強になりました。

     a_かずき_さん、miuras_netさん、trapemiyaさん大変貴重な意見を下さり
    ありがとうござました。

     それから、質問ついでなのですが(質問をする前に全然時間をかけて調べるというこ
    とをしていないので恐縮ですが)Sessionの内容は常にシリアル化されて保存されると
    思っていたのですが外部サーバにSessionを保存するときだけシリアル化するのでし
    ょうか?

     みなさん、よろしくお願いします。

    2009年12月4日 4:34
  • セッション状態モードがSQLServerとStateServerの場合はシリアライズされるようです。

    セッション状態モード
    http://msdn.microsoft.com/ja-jp/library/ms178586(VS.80).aspx


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    2009年12月4日 6:46
    モデレータ
  •  trapemiyaさん、こんにちは。

    答えて下さりありがとうございます。

    SQLServerとStateServer以外だと格納するオブジェクトは
    シリアル化できなくてもいいんですね。

     いつのまにか頭の中で勝手にSessionに格納するオブジェクトはシリアル化
    できる必要があると覚えていました。

    大変勉強になりました。
    ありがとうございました。

    2009年12月4日 9:50
  • > いつのまにか頭の中で勝手にSessionに格納するオブジェクトはシリアル化
    > できる必要があると覚えていました。

    ViewState と混同されているのではないでしょうか。
    2009年12月4日 13:31
  • SurferOnWwwさん、こんにちは。

     以前、このフォーラムで大変お世話になったものです。
    その節はありがとうございました。


    >ViewState と混同されているのではないでしょうか。

     ということですが、それでは無いと思います。
    しかし、どこでそう思ったのかはっきりと分からない
    ところが苦しいですが。

     うーん、でももしかするとViewStateがBase64
    エンコードでシリアル化されるから、それでSession
    もシリアル化されるのだと混同していたのかもしれません。

     ちょっと、どこでそう思ってしまったのか
    今となっては申し訳ありませんが分かりません。

    2009年12月5日 0:07