【问题标题】:ASP.NET MVC Session vs Global vs CacheASP.NET MVC 会话 vs 全局 vs 缓存
【发布时间】:2011-06-09 16:42:28
【问题描述】:

我有一个用普通 ASP.NET 编写的应用程序,我想将它移植到 ASP.NET MVC。

然而,我对持久化对象的正确位置感到困惑。我需要坚持有几个原因:

  1. 我希望所有人都有一个单一数据库连接,包装在“存储库”或“管理器”样式的对象中。
  2. 每个用户都有一个用户对象,需要在每个会话的基础上进行保存。

通常情况下,我会说 #1 将保存为 Globals.asax 中的静态项目,可以使用 Global.Repository 或类似的方法点击。

我通常会说#2 应该是一个在页面基类中某处具有会话支持存储的属性。

现在我感到困惑的原因是我听说 MVC 中的会话发生了变化,并且 Global.asax 不再具有相同的类。此外,页面的概念已被删除,因此向控制器的基类添加属性似乎......错误。

你说什么?

【问题讨论】:

    标签: asp.net-mvc caching session-state


    【解决方案1】:

    您的数据库将放在控制器的基类中。这个基类应该扩展 Controller,你所有的控制器都应该扩展基类。这是一个小例子:

    public class BaseController : Controller
    {
        private AuthServices _auth;
        private LogHelper _log;
        private Repository _repository;
    
        /// <summary>
        /// <see cref="AuthServices"/>
        /// </summary>
        protected AuthServices Authorization
        {
            get { return _auth ?? (_auth = new AuthServices()); }
        }
    
        /// <summary>
        /// <see cref="LogHelper"/>
        /// </summary>
        protected LogHelper Log
        {
            get { return _log ?? (_log = new LogHelper()); }
        }
    
        /// <summary>
        /// <see cref="Repository"/>
        /// </summary>
        protected Repository Repository
        {
            get { return _repository ?? (_repository = new Repository()); }
        }
    }
    

    注意惰性实例化。这使我可以在运行测试之前潜入并使用模拟设置我的私有字段。

    对于会话,您的用户对象仍然可以保存在会话中,就像在传统的 ASP.NET 应用程序中一样。几乎所有东西都还在(响应、缓存、会话等),但其中一些已经用 System.Web.Abstractions 中的类包装,以便可以模拟它们进行测试。它们的行为方式仍然相同,尽管您不应该在它们的传统角色中使用它们中的一些(例如,不要 Response.Redirect,返回一个 ActionResult,例如执行重定向的 RedirectToRouteResult)。

    至于你的问题背后的推理......

    不要强调单个数据库连接。根据您的实施,这甚至可能不是一个好主意,因为请求可能会相互影响。只需打开您的连接,使用它,完成后处理/关闭它。

    此外,MVC 带来的最大变化之一是拒绝了传统 ASP.NET 试图为 Web 开发带来的有状态模型。所有这些框架和视图状态都不再存在(不要注意幕后的人)。您持有的状态越少,您的 Web 应用程序就越不复杂且越健壮。试试看,你可能会喜欢。

    【讨论】:

    • “注意惰性实例化。这让我可以在运行测试之前潜入并使用模拟设置我的私有字段。”为什么不使用 IoC?
    • 我实际上使用了连接池。无论如何,谢谢。这几乎正​​是我的计划,很高兴知道我正在遵循相当接近最佳实践。
    【解决方案2】:

    如果您使用会话,我建议您使用会话类,这样您只需要在代码中指定一次字符串名称,这也会为您提供 IntelliSence。

     public static class SessionHandler
    {   
        // User Values
        private static string _userID = "UserID";
        private static string _userRole = "UserRole";
    
        public static string UserID
        {
            get
            {
                if (HttpContext.Current.Session[SessionHandler._userID] == null)
                { return string.Empty; }
                else
                { return HttpContext.Current.Session[SessionHandler._userID].ToString(); }
            }
            set
            { HttpContext.Current.Session[SessionHandler._userID] = value; }
    
        }
    
        public static string UserRole
        {
            get
            {
                if (HttpContext.Current.Session[SessionHandler._userRole] == null)
                { return string.Empty; }
                else
                { return HttpContext.Current.Session[SessionHandler._userRole].ToString(); }
            }
            set
            { HttpContext.Current.Session[SessionHandler._userRole] = value; }
    
        }
    }
    

    【讨论】:

    • 我喜欢这个,但是必须为每个控制器创建一个实例。我宁愿让会话中的所有控制器共享基于会话的对象,所以我将把它们作为属性放在 BaseController 类中。
    【解决方案3】:

    在 MVC 中会话完全没有改变。 Global.asax 中的 GlobalApplication 类也仍然存在。页面也存在,您希望引用控制器中的存储库而不是页面。向基本控制器类添加属性很好;我一直这样做。

    【讨论】:

      【解决方案4】:

      您可以创建模型绑定器来封装状态。

      (参见 Steve Sanderson 关于他的购物车实现的 mvc 书)

      使用模型绑定器,您可以访问具有 HttpContext 的 controllerContext。

      【讨论】:

        猜你喜欢
        • 2010-10-07
        • 1970-01-01
        • 2015-03-13
        • 1970-01-01
        • 2010-11-14
        • 1970-01-01
        • 1970-01-01
        • 2013-12-27
        • 1970-01-01
        相关资源
        最近更新 更多