做强类型ASP.NET MVC会话的更好方法

我正在开发一个ASP.NET MVC项目,并希望使用强类型的会话对象。 我已实现以下Controller派生类来公开此对象:

public class StrongController : 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]; } } } 

这允许我为每个控制器定义一个会话对象,这符合控制器隔离的概念。 是否有更好/更“正确”的方式,也许是微软正式支持的方式?

这样,其他对象将无法访问此对象(例如ActionFilter)。 我是这样做的:

 public interface IUserDataStorage { T Access { get; set; } } public class HttpUserDataStorage: IUserDataStorage 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 objectData) { } } 

当然,对于所有控制器都需要这种情况的情况(例如ICurrentUser),您可能希望使用属性注入。

这可能对你想要的更好。 我只想创建一个可以访问会话的扩展方法。 扩展方法的附加好处是您不再需要从控制器inheritance,或者必须注入实际上不必开始的依赖项。

 public static class SessionExtensions { public static T Get(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("chocolate"); return View(); } } 

http://codingsmith.co.za/a-better-way-of-working-with-httpcontext-session-in-mvc/ (我的博客上的颜色道歉是主题的工具,还没有修复它)

 public interface ISessionCache { T Get(string key); void Set(string key, T item); bool contains(string key); void clearKey(string key); T singleTon(String key, getStuffAction actionToPerform); } public class InMemorySessionCache : BaseSessionCache { Dictionary _col; public InMemorySessionCache() { _col = new Dictionary(); } public T Get(string key) { return (T)_col[key]; } public void Set(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(string key) { object value = _context.Session[key]; return value == null ? default(T) : (T)value; } public void Set(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; } } 

几年前我想出了它,它运行正常。 和其他人一样基本的想法我猜,为什么微软不会像标准那样实现这一点。

我通常将它用于会话密钥,然后根据需要显式添加对象。 这样做的原因是它是一种干净的方式,我发现你想要将会话中的对象数量保持在最低限度。

这种特殊的方法将表单身份validation和用户会话集中到一个地方,因此您可以添加对象并忘记它。 可以说它是一个很大的冗长,但它确实可以防止任何加倍,你不应该在会话中有太多的对象。

以下内容可以存在于核心库中,也可以存在于任何位置。

  ///  /// Provides a default pattern to access the current user in the session, identified /// by forms authentication. ///  public abstract class MySession where T : class { public const string USERSESSIONKEY = "CurrentUser"; ///  /// Gets the object associated with the CurrentUser from the session. ///  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(); } ///  /// Implement this method to load the user object identified by username. ///  /// The username of the object to retrieve. /// The user object associated with the username 'username'. protected abstract T LoadCurrentUser(string username); } } 

然后在命名为项目根目录的下一个类中实现它(我通常把它放在mvc项目的代码文件夹中):

 public class CurrentSession : MySession { 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; } } } 

最后在会话中明确声明你想要的东西的最大优点是你可以在你的mvc应用程序中的任何地方引用它,包括视图。 只需参考:

 CurrentSession.Instance.Object1 CurrentSession.Instance.CurrentUser 

再次比其他方法更不通用,但真正清楚发生了什么,没有其他索具或dependency injection,并且对请求上下文100%安全。

另一方面,dicionary方法很酷,但你仍然最终会在整个地方使用字符串来引用内容。 您可以使用枚举或其他东西进行assembly,但我更喜欢强类型和设置而忘记上述方法。

是的,问这个问题已经有好几年了,还有其他方法可以做到这一点……但是如果有其他人出现寻找将上述方法结合到一个吸引人的一站式商店的事情(至少有一个吸引我的团队而我……)这是我们使用的。

  public enum SessionKey { CurrentUser, CurrentMember, CurrentChart, CurrentAPIToken, MemberBanner } public static class SessionCache { public static T Get(this HttpSessionStateBase session, SessionKey key) { var value = session[key.ToString()]; return value == null ? default(T) : (T) value; } public static void Set(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(SessionKey.CurrentMember); // set member Session.Set(SessionKey.CurrentMember, currentMember); // clear member Session.ClearKey(SessionKey.CurrentMember); // get member if in session if (Session.Contains(SessionKey.CurrentMember)) { var current = Session.Get(SessionKey.CurrentMember); } 

希望这有助于某人!