在 ASP.NET MVC 站点中实现 Session 的公认模式是啥?

Posted

技术标签:

【中文标题】在 ASP.NET MVC 站点中实现 Session 的公认模式是啥?【英文标题】:What is the accepted pattern for implementing Session in ASP.NET MVC sites?在 ASP.NET MVC 站点中实现 Session 的公认模式是什么? 【发布时间】:2011-01-24 08:09:45 【问题描述】:

显然,典型的 WebForms 方法行不通。在 MVC 世界中如何跟踪用户?

【问题讨论】:

我自己对此很感兴趣。我个人想保留一个面包屑痕迹,但我不想在查询字符串中传递它。您具体想跟踪用户的哪些方面? 什么是行不通的“典型 WebForms 方法”? 【参考方案1】:

Session 的工作方式与它在 Webforms 中的工作方式完全相同。如果要存储简单信息,请使用表单身份验证 cookie。如果你想存储购物车的内容,Session 是你可以去的地方。我写了一篇关于using Session with ASP.NET的博文:

假设我们想在 Session 中存储一个整数变量。我们将创建 Session 变量的包装器,使其看起来更好:

首先我们定义接口:

public interface ISessionWrapper

    int SomeInteger  get; set; 

然后我们实现HttpContext:

public class HttpContextSessionWrapper : ISessionWrapper

    private T GetFromSession<T>(string key)
    
        return (T) HttpContext.Current.Session[key];
    

    private void SetInSession(string key, object value)
    
        HttpContext.Current.Session[key] = value;
    

    public int SomeInteger
    
        get  return GetFromSession<int>("SomeInteger"); 
        set  SetInSession("SomeInteger", value); 
    

GetFromSession 和 SetInSession 是帮助在 Session 中获取和设置数据的方法。 SomeInteger 属性使用这些方法。

然后我们定义我们的基础控制器(适用于 ASP.NET MVC):

public class BaseController : Controller

    public ISessionWrapper SessionWrapper  get; set; 

    public BaseController()
    
        SessionWrapper = new HttpContextSessionWrapper();
    

如果你想在控制器外使用 Session,你只需创建或注入新的 HttpContextSessionWrapper()。

您可以在 Controller 测试中将 SessionWrapper 替换为 ISessionWrapper 模拟,因此它不再依赖于 HttpContext。 Session 也更易于使用,因为您调用的是 SessionWrapper.SomeInteger,而不是调用 (int)Session["SomeInteger"]。它看起来更好,不是吗?

您可能会被创建覆盖 Session 对象的静态类的想法所吸引,并且不需要在 BaseController 中定义任何接口或初始化,但它失去了一些优势,特别是在测试和替换其他实现时。

【讨论】:

当框架已经为您提供HttpContext.Current.Session[key]时,您为什么还要编写接口和包装类? 因为:1. var cart = (List)HttpContext.Current.Session[key] 看起来很丑,而 SessionWrapper.CartItems 看起来不错。 2. ISessionWrapper 更容易编写测试。 ISessionWrapper 可以轻松模拟并替换为各种测试场景的内容。 3.它失去了依赖。如果我想使用另一个存储而不是 Session,我只需创建其他 ISessionWrapper 实现。您必须替换每个使用 Session 的控制器中的代码。 优点。尽管除非您编辑了帖子,否则我无法收回反对票。 在函数中使用会话会杀死单元测试。使用接口会话助手/包装器是解决此问题的好方法,而不会丢失功能。【参考方案2】:

这是我使用的代码,只是上述版本的一点“改进”版本:

private T GetFromSessionStruct<T>(string key, T defaultValue = default(T)) where T : struct 

    object obj = HttpContext.Current.Session[key];
    if (obj == null)
    
        return defaultValue;
    
    return (T)obj;


private T GetFromSession<T>(string key) where T : class

    object obj = HttpContext.Current.Session[key];
    return (T)obj;


private T GetFromSessionOrDefault<T>(string key, T defaultValue = null) where T : class

    object obj = HttpContext.Current.Session[key];
    if (obj == null)
    
        return defaultValue ?? default(T);
    
    return (T)obj;


private void SetInSession<T>(string key, T value)

    if (value == null)
    
        HttpContext.Current.Session.Remove(key);
    
    else
    
        HttpContext.Current.Session[key] = value;
    

【讨论】:

你将如何实现,你能告诉我们上面代码的几个例子

以上是关于在 ASP.NET MVC 站点中实现 Session 的公认模式是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 Visual Studio 的情况下使用 ASP.NET MVC 实现站点?

在 ASP.net MVC 站点中查看 s-s-rS 报告

使用 ASP.NET 核心 MVC/Razor 站点和 WebAPI 进行授权

使用 ASP.NET MVC 实现字段验证的最佳方法是啥? [关闭]

在 ASP.NET Core 站点中实现 Blazor - 组件不在视图中呈现

有没有办法让 Asp.net 零公共站点(Asp.net MVC)中的实时登录用户?