ASP.NET MVCのセッション変数


169

ユーザーが特定のリクエストを行うWebサイト内の複数のWebページを閲覧できるようにするWebアプリケーションを作成しています。ユーザーが入力するすべての情報は、私が作成したオブジェクトに格納されます。問題は、このオブジェクトにWebサイトのどの部分からでもアクセスする必要があり、これを達成するための最良の方法が本当にわからないことです。1つの解決策はセッション変数を使用することですが、asp .net MVCでそれらを使用する方法はわかりません。そして、どこでセッション変数を宣言しますか?他に方法はありますか?


3
あなたはWebサイトとWebアプリケーションの概念を混ぜ合わせています...それらは同じものではありません。
adripanico 2012年

1
データベースの必要性のように聞こえる
Coops '12 / 12/05

回答:


123

物事が本当にセッションステートに属しているかどうかについて考えたいと思います。これは私が時々やっていることですが、全体に対して強く型付けされたアプローチですが、セッションコンテキストに物事を入れるときは注意する必要があります。一部のユーザーに属しているからといって、すべてが存在するわけではありません。

global.asaxでOnSessionStartイベントをフックする

void OnSessionStart(...)
{
    HttpContext.Current.Session.Add("__MySessionObject", new MySessionObject());
}

HttpContext.Currentプロパティ!= nullであるコードのどこからでも、そのオブジェクトを取得できます。私はこれを拡張メソッドで行います。

public static MySessionObject GetMySessionObject(this HttpContext current)
{
    return current != null ? (MySessionObject)current.Session["__MySessionObject"] : null;
}

このようにコードでできます

void OnLoad(...)
{
    var sessionObj = HttpContext.Current.GetMySessionObject();
    // do something with 'sessionObj'
}

32
ASP MVCが使用されている場合、HttpContext.Current.Sessionからの実際のSessionオブジェクトを使用するのではなく、System.Web.Abstractions.dllからの新しいHttpSessionStateWrapper&HttpSessionStateBaseを使用して、ファクトリまたはDIを使用してセッションを取得することをお勧めします。
ポール、

6
どのようにセッション変数に何かを割り当てますか?(単にアクセスするのではなく)
raklos

31
「OnSessionStart」イベントとは何か、どのように「フック」するかを理解しようとしている人は、stackoverflow.com
questions / 1531125 /…

5
@Paul例を提供できますか?HttpSessionStateWrapperの使用例を見つけられないようです。
Joseph Woodward

4
このコメントスレッドは示唆し@AjayKelkarあなたの答えを示唆していることではない、より良い「ASP MVCを使用している場合、HttpContext.Current.Sessionから実際のSessionオブジェクトを使用しないことではなく、新たなHttpSessionStateWrapper&HttpSessionStateBase使用することが望ましい」
小屋

48

ここでの答えは正しいですが、ASP.NET MVC 3アプリに実装するのに苦労しました。コントローラ内のSessionオブジェクトにアクセスしたいのですが、「インスタンスがオブジェクトエラーのインスタンスに設定されていません」というエラーが発生し続ける理由がわかりませんでした。私が気付いたのは、コントローラーで次のようにしてセッションにアクセスしようとすると、エラーが発生し続けるということです。これは、this.HttpContextがControllerオブジェクトの一部であるためです。

this.Session["blah"]
// or
this.HttpContext.Session["blah"]

しかし、私が欲しかったのは、System.Web名前空間の一部であるHttpContextでした。これは、上記の回答がGlobal.asax.csで使用することを示唆しているものだからです。だから私は明示的に次のことをしなければなりませんでした:

System.Web.HttpContext.Current.Session["blah"]

これは私を助けました、私がこの辺りでMOではないことをしたかどうかはわかりませんが、誰かの助けになれば幸いです!


6
System.Web.HttpContext.Current.Session ["blah"] = value
Tomasz Iniewicz '27 / 07/12

21

場所に関する "HTTPContext.Current.Session"を見たくないので、シングルトンパターンを使用してセッション変数にアクセスします。これにより、厳密に型指定されたデータのバッグに簡単にアクセスできます。

[Serializable]
public sealed class SessionSingleton
{
    #region Singleton

    private const string SESSION_SINGLETON_NAME = "Singleton_502E69E5-668B-E011-951F-00155DF26207";

    private SessionSingleton()
    {

    }

    public static SessionSingleton Current
    {
        get
        {
            if ( HttpContext.Current.Session[SESSION_SINGLETON_NAME] == null )
            {
                HttpContext.Current.Session[SESSION_SINGLETON_NAME] = new SessionSingleton();
            }

            return HttpContext.Current.Session[SESSION_SINGLETON_NAME] as SessionSingleton;
        }
    }

    #endregion

    public string SessionVariable { get; set; }
    public string SessionVariable2 { get; set; }

    // ...

その後、どこからでもデータにアクセスできます。

SessionSingleton.Current.SessionVariable = "Hello, World!";

2
したがって、このクラスには2つの責任があります。単一のインスタンスを維持し、変数を格納します... IOCコンテナーを使用してシングルトンを作成します。
Jowen

1
すでに1つの設定をしている場合は、おそらく本格的な注入可能なセッションサービスも作成しますが、一貫性がおそらく最大の利点です。この機能を小さな機能セットのWebアプリケーションに使用する傾向があります。
Dead.Rabit 2013年

14

asp.net mvcを使用している場合、セッションにアクセスする簡単な方法を次に示します。

コントローラから:

{Controller}.ControllerContext.HttpContext.Session["{name}"]

ビューから:

<%=Session["{name}"] %>

これは間違いなくセッション変数にアクセスするための最良の方法ではありませんが、直接的な方法です。したがって、(できればラピッドプロトタイピング中に)注意して使用し、適切になった場合はWrapper / ContainerとOnSessionStartを使用してください。

HTH


2
hm ..どちらが最善の方法ですか?コントローラのセッションからViewStateにデータを渡す必要がありますか?
RredCat 2011

2
そして、あなたはこの方法の狭窄を説明できますか?
RredCat 2011

1
彼は、読み取り/書き込みメソッドを用意するのが最善であることを意味していると思います。同時実行性/スレッドの使用状況によっては、競合状態を回避するために、これらの読み取り/書き込みメソッドでロックが必要になる場合もあります。
DeepSpace101、2012

13

まあ、私見..

  1. ビュー/マスターページ内でセッションを参照しない
  2. セッションの使用を最小限に抑えます。MVCは、このためのTempData objを提供します。これは、基本的には、サーバーへの1回のトリップで存続するセッションです。

#1に関しては、Sessionオブジェクトが表すものにアクセスするためのプロパティを持つ、強く型付けされたマスタービューがあります。

ViewMasterPage<AdminViewModel>

AdminViewModel
{
    SomeImportantObjectThatWasInSession ImportantObject
}

AdminViewModel<TModel> : AdminViewModel where TModel : class
{
   TModel Content
}

その後...

ViewPage<AdminViewModel<U>>

7

asp.net mvcについてはわかりませんが、通常の.net Webサイトではこれを行う必要があります。asp.net mvcでも動作するはずです。

YourSessionClass obj=Session["key"] as YourSessionClass;
if(obj==null){
obj=new YourSessionClass();
Session["key"]=obj;
}

簡単にアクセスできるように、これをメソッド内に配置します。HTH


7

それを行うには3つの方法があります。

  1. 直接アクセスできます HttpContext.Current.Session

  2. あなたはモックすることができます HttpContextBase

  3. 拡張メソッドを作成する HttpContextBase

私は3番目の方法を好みます。このリンクは参考資料です。

Get / Setメソッドを作成するためにBaseControllerでHttpContextセッションメソッドを取得/設定するか、HttpContextBaseをモックする


7

セッションにアクセスする私の方法は、さまざまなフィールド名とそのタイプをカプセル化するヘルパークラスを記述することです。この例が役立つことを願っています:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.SessionState;

namespace dmkp
{
    /// <summary>
    /// Encapsulates the session state
    /// </summary>
    public sealed class LoginInfo
    {
        private HttpSessionState _session;
        public LoginInfo(HttpSessionState session)
        {
            this._session = session;
        }

        public string Username
        {
            get { return (this._session["Username"] ?? string.Empty).ToString(); }
            set { this._session["Username"] = value; }
        }

        public string FullName
        {
            get { return (this._session["FullName"] ?? string.Empty).ToString(); }
            set { this._session["FullName"] = value; }
        }
        public int ID
        {
            get { return Convert.ToInt32((this._session["UID"] ?? -1)); }
            set { this._session["UID"] = value; }
        }

        public UserAccess AccessLevel
        {
            get { return (UserAccess)(this._session["AccessLevel"]); }
            set { this._session["AccessLevel"] = value; }
        }

    }
}

私はあなたの答えが好きです...あなたは何が起こっているのかさらに詳しく説明できますか?そしてなぜこれがこのスレッドの他の答えとは対照的なより良いアプローチであるのですか?
Chef_Code

6

皆さんからの素晴らしい回答ですが、常にセッションに依存することはお勧めしません。これはすばやく簡単に実行でき、もちろん機能しますが、すべての状況で優れているわけではありません。

たとえば、ホスティングでセッションの使用が許可されていないシナリオに遭遇した場合、Webファームを使用している場合、または共有SharePointアプリケーションの例などです。

別のソリューションが必要な場合は、Castle WindsorなどのIOCコンテナの使用を検討してください。、プロバイダークラスをラッパーとして作成し、要件に応じて要求ごとまたはセッションライフスタイルを使用してクラスの1つのインスタンスを保持ます。

IOCは、毎回同じインスタンスが返されることを保証します。

もっと複雑です。単純なソリューションが必要な場合は、セッションを使用してください。

以下は、関心のある以下の実装例です。

このメソッドを使用すると、次の行に沿ってプロバイダークラスを作成できます。

public class CustomClassProvider : ICustomClassProvider
{
    public CustomClassProvider(CustomClass customClass)
    { 
        CustomClass = customClass;
    }

    public string CustomClass { get; private set; }
}

そしてそれを次のように登録します:

public void Install(IWindsorContainer container, IConfigurationStore store)
{
    container.Register(
            Component.For<ICustomClassProvider>().UsingFactoryMethod(
                () => new CustomClassProvider(new CustomClass())).LifestylePerWebRequest());
    }

4

ViewModelBaseをすべてのモデルの基本クラスとして使用できます。このクラスがセッションからデータをプルします

class ViewModelBase 
{
  public User CurrentUser 
  {
     get { return System.Web.HttpContext.Current.Session["user"] as User };
     set 
     {
        System.Web.HttpContext.Current.Session["user"]=value; 
     }
  }
}

HttpContextBaseに拡張メソッドを記述して、セッションデータを処理できます。

T FromSession<T>(this HttpContextBase context ,string key,Action<T> getFromSource=null) 
{
    if(context.Session[key]!=null) 
    {
        return (T) context.Session[key];
    }
  else if(getFromSource!=null) 
  {
    var value = getFromSource();
   context.Session[key]=value; 
   return value; 
   }
  else 
  return null;
}

コントローラで以下のように使用します

User userData = HttpContext.FromSession<User>("userdata",()=> { return user object from service/db  }); 

2番目の引数はオプションです。セッションに値が存在しない場合、そのキーのセッションデータを埋めるために使用されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.