2009-11-10 7 views
19

करने का बेहतर तरीका मैं एक एएसपी.नेट एमवीसी प्रोजेक्ट विकसित कर रहा हूं और दृढ़ता से टाइप किए गए सत्र ऑब्जेक्ट्स का उपयोग करना चाहता हूं। मैं इस वस्तु का पर्दाफाश करने के लिए निम्न नियंत्रक-व्युत्पन्न वर्ग को लागू किया है:दृढ़ता से टाइप किए गए एएसपी.नेट एमवीसी सत्र

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

इस तरह अन्य ऑब्जेक्ट्स को इस ऑब्जेक्ट तक पहुंच नहीं होगी (जैसे एक्शनफिल्टर)। मैं इसे इस तरह कार्य करें:

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 < टी >)) का उपयोग करें।

public class MyController: Controller 
{ 
    // automatically passed by IoC container 
    public MyController(IUserDataStorage<MyObject> objectData) 
    { 
    } 
} 
मामलों के लिए बेशक

सभी नियंत्रकों इस (जैसे ICurrentUser) की जरूरत है जब आप के बजाय संपत्ति इंजेक्शन का उपयोग कर सकते हैं।

+0

मुझे यह काफी पसंद है। मैं HttpContext के बारे में भूल गया। –

+0

जब आप निर्भरता इंजेक्शन के लिए एकता का उपयोग करते हैं तो यह कैसे काम करता है वर्तमान प्रकार, 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/ (अपने ब्लॉग पर रंग के लिए क्षमा याचना विषयों के साथ चारों ओर टूलींग था और बस नहीं किया यह अभी तक तय)

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

} 

तो निम्न वर्ग अपनी परियोजना की जड़ तक namespaced में यह लागू (मैं आमतौर पर MVC परियोजनाओं पर एक कोड फ़ोल्डर में रख दें) सत्र में आप जो चाहते हैं वह यह है कि आप विचारों सहित अपने एमवीसी आवेदन में इसे कहीं भी संदर्भित कर सकते हैं। बस के साथ इसे संदर्भ:

CurrentSession.Instance.Object1 
CurrentSession.Instance.CurrentUser 

फिर अन्य तरीकों से थोड़ा कम सामान्य, लेकिन वास्तव में वास्तव में स्पष्ट क्या हो रहा है, कोई अन्य हेराफेरी या dependancy इंजेक्शन और 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); 
} 

उम्मीद है कि इससे किसी की मदद मिलती है!