2009-11-10 10 views
19

私はASP.NET MVCプロジェクトを開発しており、強く型付けされたセッションオブジェクトを使いたいと思っています。私はこのオブジェクトを公開するために、次のコントローラの派生クラスを実装している:これは私は、コントローラ分離の概念に沿ったものである各コントローラのためのセッション・オブジェクトを定義することができ強く型付けされたASP.NET MVCセッションのより良い方法

public class StrongController<_T> : Controller 
    where _T : new() 
{ 
    public _T SessionObject 
    { 
     get 
     { 
      if (Session[typeof(_T).FullName] == null) 
      { 
       _T newsession = new _T(); 
       Session[typeof(_T).FullName] = newsession; 
       return newsession; 
      } 
      else 
       return (_T)Session[typeof(_T).FullName]; 
     } 
    } 

} 

。より良い/より "正しい"方法、おそらくMicrosoftによって正式にサポートされているものがありますか?

+0

複数のコントローラに同じタイプを渡すとどうなりますか? 1つのセッションでもう一方のセッションが上書きされますか? –

+0

いいえ、どちらも同じタイプ名を持ち、同じセッションキーを持ちます。セッションオブジェクトは置き換えられず、両方のコントローラで同じオブジェクトになります。 –

+0

下に追加されたのは、ベースコントローラを必要とせず、ビューコードでセッションにアクセスすることもできます。 – Gats

答えて

18

このようにして、他のオブジェクトはこのオブジェクトにアクセスできなくなります(例:ActionFilter)。

public interface IUserDataStorage<T> 
{ 
    T Access { get; set; } 
} 

public class HttpUserDataStorage<T>: IUserDataStorage<T> 
    where T : class 
{ 
    public T Access 
    { 
    get { return HttpContext.Current.Session[typeof(T).FullName] as T; } 
    set { HttpContext.Current.Session[typeof(T).FullName] = value; } 
    } 
} 

その後、私は、コントローラのコンストラクタにIUserDataStorageを注入、またはServiceLocator.Current.GetInstance(typeof演算(IUserDataStorage <T>))を使用することができますいずれかのActionFilter内側:私はこのようにそれを行います。例のための当然の

public class MyController: Controller 
{ 
    // automatically passed by IoC container 
    public MyController(IUserDataStorage<MyObject> objectData) 
    { 
    } 
} 

すべてコントローラがあなたの代わりにプロパティインジェクションを使用することもできます(例えばICurrentUser)これを必要とする場合

+0

私はこれがかなり好きです。私はHttpContextを忘れていました。 –

+0

依存性注入にunityを使用すると、これはどのように動作するか現在の型Main.Services.IUserDataStorage'1 [sipObjects.HandyGuy]はインタフェースであり、構築できません。型マッピングがありませんか? – HaBo

+0

ここに何かが見つかりましたhttp://msdn.microsoft.com/en-us/library/ff660936(v=pandp.20).aspx – HaBo

4

これは、お望みの方が良いかもしれません。あなたのセッションにアクセスできる拡張メソッドを作成するだけです。拡張メソッドの追加の利点は、もはやコントローラから継承する必要がなくなったか、または本当に始める必要のない依存関係を注入する必要があるということです。

public static class SessionExtensions { 
    public static T Get<T>(this HttpSessionBase session, string key) { 
    var result; 
    if (session.TryGetValue(key, out result)) 
    { 
     return (T)result; 
    } 
    // or throw an exception, whatever you want. 
    return default(T); 
    } 
} 


public class HomeController : Controller { 
    public ActionResult Index() { 
     //.... 

     var candy = Session.Get<Candy>("chocolate"); 

     return View(); 
    } 

} 
+0

これはいいですね。 +1 – Darbio

2

http://codingsmith.co.za/a-better-way-of-working-with-httpcontext-session-in-mvc/(私のブログ上の色のための謝罪は、テーマと周りのツーリングだったため、まだそれを修正haventは)

public interface ISessionCache 
{ 
    T Get<T>(string key); 
    void Set<T>(string key, T item); 
    bool contains(string key); 
    void clearKey(string key); 
    T singleTon<T>(String key, getStuffAction<T> actionToPerform); 
} 


public class InMemorySessionCache : BaseSessionCache 
{ 
    Dictionary<String, Object> _col; 
    public InMemorySessionCache() 
    { 
     _col = new Dictionary<string, object>(); 
    } 

    public T Get<T>(string key) 
    { 
     return (T)_col[key]; 
    } 

    public void Set<T>(string key, T item) 
    { 
     _col.Add(key, item); 
    } 

    public bool contains(string key) 
    { 
     if (_col.ContainsKey(key)) 
     { 
      return true; 
     } 
     return false; 
    } 

    public void clearKey(string key) 
    { 
     if (contains(key)) 
     { 
      _col.Remove(key); 
     } 
    } 
} 



public class HttpContextSessionCache : BaseSessionCache 
{ 
    private readonly HttpContext _context; 

    public HttpContextSessionCache() 
    { 
     _context = HttpContext.Current; 
    } 

    public T Get<T>(string key) 
    { 
     object value = _context.Session[key]; 
     return value == null ? default(T) : (T)value; 
    } 

    public void Set<T>(string key, T item) 
    { 
     _context.Session[key] = item; 
    } 

    public bool contains(string key) 
    { 
     if (_context.Session[key] != null) 
     { 
      return true; 
     } 
     return false; 
    } 
    public void clearKey(string key) 
    { 
     _context.Session[key] = null; 
    } 
} 

は、私が数年前にそれを思い付いた、それが正常に動作します。他のみんなと同じ基本的なアイデアだと思います。なぜマイクロソフトがこれを標準として実装していないのですか?

0

私は一般にこれをセッションキーに使用し、必要に応じて明示的にオブジェクトを追加します。その理由は、それを行うためのきれいな方法であり、セッションのオブジェクト数を最小限に抑えたいと思うからです。

この特定のアプローチでは、フォーム認証とユーザーセッションを1つの場所に集約して、オブジェクトを追加して忘れることができます。議論は、それが大きな冗長であることができるかもしれませんが、それはダブルアップを防ぎ、あなたはセッション中にあまりにも多くのオブジェクトを持つべきではありません。

以下は、コアライブラリまたは任意の場所に存在する可能性があります。明示的に宣言するの

public class CurrentSession : MySession<PublicUser> 
{ 
    public static CurrentSession Instance = new CurrentSession(); 

    protected override PublicUser LoadCurrentUser(string username) 
    { 
     // This would be a data logic call to load a user's detail from the database 
     return new PublicUser(username); 
    } 

    // Put additional session objects here 
    public const string SESSIONOBJECT1 = "CurrentObject1"; 
    public const string SESSIONOBJECT2 = "CurrentObject2"; 

    public Object1 CurrentObject1 
    { 
     get 
     { 
      if (Session[SESSIONOBJECT1] == null) 
       Session[SESSIONOBJECT1] = new Object1(); 

      return Session[SESSIONOBJECT1] as Object1; 
     } 
     set 
     { 
      Session[SESSIONOBJECT1] = value; 
     } 
    } 

    public Object2 CurrentObject2 
    { 
     get 
     { 
      if (Session[SESSIONOBJECT2] == null) 
       Session[SESSIONOBJECT2] = new Object2(); 

      return Session[SESSIONOBJECT2] as Object2; 
     } 
     set 
     { 
      Session[SESSIONOBJECT2] = value; 
     } 
    } 
} 

FINALLY 大きな利点:

/// <summary> 
    /// Provides a default pattern to access the current user in the session, identified 
    /// by forms authentication. 
    /// </summary> 
    public abstract class MySession<T> where T : class 
    { 
     public const string USERSESSIONKEY = "CurrentUser"; 

     /// <summary> 
     /// Gets the object associated with the CurrentUser from the session. 
     /// </summary> 
     public T CurrentUser 
     { 
      get 
      { 
       if (HttpContext.Current.Request.IsAuthenticated) 
       { 
        if (HttpContext.Current.Session[USERSESSIONKEY] == null) 
        { 
         HttpContext.Current.Session[USERSESSIONKEY] = LoadCurrentUser(HttpContext.Current.User.Identity.Name); 
        } 
        return HttpContext.Current.Session[USERSESSIONKEY] as T; 
       } 
       else 
       { 
        return null; 
       } 
      } 
     } 

     public void LogOutCurrentUser() 
     { 
      HttpContext.Current.Session[USERSESSIONKEY] = null; 
      FormsAuthentication.SignOut(); 
     } 

     /// <summary> 
     /// Implement this method to load the user object identified by username. 
     /// </summary> 
     /// <param name="username">The username of the object to retrieve.</param> 
     /// <returns>The user object associated with the username 'username'.</returns> 
     protected abstract T LoadCurrentUser(string username); 
    } 

} 

次に、あなたのプロジェクトのルートに名前空間以下のクラスでこれを実装する(私は通常、MVCプロジェクトのコードのフォルダに入れて)あなたがセッションで欲しいのは、ビューを含め、あなたのmvcアプリケーション内のどこでもこれを絶対に参照できるということです。何が起こっているのか、他の談合や依存性の注入と要求コンテキストへの安全な100%、他のアプローチよりも

CurrentSession.Instance.Object1 
CurrentSession.Instance.CurrentUser 

ここでも少し一般的な、しかし本当に明確な:ちょうどでそれを参照しません。

別のノートでは、大胆なアプローチはクールですが、あなたはまだ参照用の場所に文字列で終わります。列挙型などでリグを作成することもできますが、私は強く入力することを好み、上記のアプローチを設定して忘れてしまいます。

0

はい、この質問が尋ねられた後、これを行う他の方法があります...しかし、他の誰かが上のアプローチを魅力的なワンストップショップ(少なくとも1つ私のチームに訴えて、私は...)ここでは、私たちが使っていることがあります。

public enum SessionKey { CurrentUser, CurrentMember, CurrentChart, CurrentAPIToken, MemberBanner } 

public static class SessionCache { 

    public static T Get<T>(this HttpSessionStateBase session, SessionKey key) 
    { 
     var value = session[key.ToString()]; 
     return value == null ? default(T) : (T) value; 
    } 

    public static void Set<T>(this HttpSessionStateBase session, SessionKey key, T item) 
    { 
     session[key.ToString()] = item; 
    } 

    public static bool contains(this HttpSessionStateBase session, SessionKey key) 
    { 
     if (session[key.ToString()] != null) 
      return true; 
     return false; 
    } 

    public static void clearKey(this HttpSessionStateBase session, SessionKey key) 
    { 
     session[key.ToString()] = null; 
    } 
} 

あなたのコントローラでは、より厳密に型付けされた方法でセッション変数を使用できます。

// get member 
var currentMember = Session.Get<Member>(SessionKey.CurrentMember); 
// set member 
Session.Set<Member>(SessionKey.CurrentMember, currentMember); 
// clear member 
Session.ClearKey(SessionKey.CurrentMember); 
// get member if in session 
if (Session.Contains(SessionKey.CurrentMember)) 
{ 
    var current = Session.Get<Member>(SessionKey.CurrentMember); 
} 

関連する問題