2009-11-10 1 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]; 
     } 
    } 

} 

. 더/더 "올바른"방법, 아마도 공식적으로 마이크로 소프트에 의해 지원되는 무언가가 있을까요?

+0

두 개 이상의 컨트롤러에 동일한 유형을 전달하면 어떻게 될까요? 한 세션이 다른 세션을 덮어 씁니 까? –

+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를 주입, 또는 ActionFilter 내부 ServiceLocator.Current.GetInstance (대해서 typeof (IUserDataStorage <T>))를 사용할 수 있습니다. 경우에 물론

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

일반적으로이 키를 세션 키로 사용하고 필요에 따라 개체를 명시 적으로 추가합니다. 그 이유는 깨끗한 방법이므로 세션의 오브젝트 수를 최소한으로 유지하려고합니다.

이 특별한 접근 방식은 양식 인증과 사용자 세션을 한 곳으로 모으기 때문에 개체를 추가하고 잊어 버릴 수 있습니다. 인수는 큰 장황함을 나타낼 수 있지만 두 배의 증가를 방지하고 세션 중에 너무 많은 객체를 가져서는 안됩니다.

다음은 코어 라이브러리 또는 원하는 곳에서 존재할 수 있습니다. 명시 적으로 선언

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; 
     } 
    } 
} 

마침내 큰 장점 :

/// <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 응용 프로그램에서이 위치를 절대적으로 참조 할 수 있다는 것입니다. 그냥 그것을 참조 : 무슨 일이 일어나고 있는지 조금 다른 방법보다 덜 일반적인, 그러나 정말 정말 선택을 다시

CurrentSession.Instance.Object1 
CurrentSession.Instance.CurrentUser 

, 다른 담합이나 의존성 주입과 100 % 요청 컨텍스트에 안전합니다.

또 다른 주목할 점은 협동 식 접근법이 멋지지만 여전히 참고 자료로 모든 곳에서 문자열을 사용한다는 것입니다. 열거 형 (enums) 등으로 장비를 조작 할 수는 있지만 위의 방법을 강하게 타자를 치고 설정하고 잊어 버리는 편이 낫습니다.

0

예, 몇 달 후에이 질문을하고 다른 방법이 있습니다 ... 다른 사람이 위의 접근법을 매력적인 원 스톱 쇼핑 (적어도 하나의 내 팀에 호소했고 나는 ...) 여기에 우리가 사용하는 것이있다.

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); 
} 

희망이 있으면 도움이 될 것입니다.