【问题标题】:Where should caching occur in an ASP.NET MVC application?在 ASP.NET MVC 应用程序中应该在哪里进行缓存?
【发布时间】:2010-09-19 02:34:18
【问题描述】:

我需要使用 System.Web.Caching.Cache 缓存一些数据。不确定是否重要,但数据不是来自数据库,而是来自大量自定义对象。

ASP.NET MVC 对我来说相当新,我想知道在哪里进行这种缓存是有意义的?

模型还是控制器?

在某种程度上,在 Model 级别进行缓存是有意义的,但我不一定知道这样做的含义(如果有的话)。如果在 Controller 级别进行缓存,会影响所有请求,还是仅影响当前的 HttpContext

那么...应该在哪里完成应用程序数据缓存,以及实际执行它的好方法是什么?

更新

感谢您的精彩回答!我仍在尝试收集在不同情况下缓存最有意义的位置。如果一个人正在缓存整个页面,那么将其保留在视图中是有意义的,但是当它不是整个页面时在哪里画线?

【问题讨论】:

    标签: asp.net-mvc caching


    【解决方案1】:

    我认为这最终取决于您正在缓存的什么。如果要缓存渲染页面的结果,这与请求的 Http 特性紧密耦合,建议使用 ActionFilter 级别的缓存机制。

    另一方面,如果您想要缓存驱动页面本身的数据,那么您应该考虑模型级缓存。在这种情况下,控制器并不关心数据何时生成,它只是对数据执行逻辑操作并准备查看。模型级缓存的另一个论点是,如果您对模型数据有其他依赖项附加到您的 Http 上下文。

    例如,我有一个网络应用程序,我的大部分模型都被抽象到一个完全不同的项目中。这是因为将会有第二个网络应用程序使用相同的支持,并且我们可能有一个基于非网络的应用程序也使用相同的数据。我的大部分数据来自网络服务,这可能是性能杀手,所以我有控制器和视图完全不知道的模型级缓存。

    【讨论】:

      【解决方案2】:

      我不知道您问题的答案,但 Jeff Atwood 在最近的 hanselminutes 节目中谈到了 SO 团队如何使用 stackoverflow.com 的 MVC 框架进行缓存,这可能会帮助您:

      http://www.hanselminutes.com/default.aspx?showID=152

      【讨论】:

      • 谢谢!有趣的是,我实际上几天前听过这个。不幸的是,我无法真正了解他们解决方案的细节。谁知道呢,这可能只是让我有点过头了。 :)
      • 我也听过这个,我不认为他们在回答这个问题时实现了缓存的在哪里很明显 - 尽管讨论和后续博客Scott Hanselman 关于压缩缓存内容的帖子非常有趣!
      【解决方案3】:

      快速解答

      我将从 CONTROLLER 缓存开始,使用OutputCache 属性,然后在需要时添加模型缓存。它实施起来更快,并且立竿见影。

      详细答案(因为我喜欢我的声音)

      这是一个例子。

      [OutputCache(Duration=60, VaryByParam="None")]
      public ActionResult CacheDemo() {
        return View();
      }
      

      这意味着如果用户点击该站点(对于属性中定义的缓存要求),需要完成的工作就会减少。如果只有模型缓存,那么即使缓存了逻辑(很可能是 DB 命中),Web 服务器仍然必须呈现页面。为什么渲染结果总是一样的?

      所以从OutputCaching 开始,然后在您对网站进行性能测试时转到模型缓存。

      输出缓存也更容易开始。您不必担心网络场分布式缓存问题(如果您是场的一部分)和模型的缓存提供程序。

      高级缓存技术

      您也可以应用甜甜圈缓存 -> 仅缓存 UI 页面的一部分 :) Check it out!

      【讨论】:

        【解决方案4】:

        我会选择模型级别的缓存。 (一般来说,建议似乎是在控制器级别最小化业务逻辑 并尽可能多地移动到模型类中。)

        这样做怎么样:

        我在Entry 类所代表的模型中有一些条目 和条目来源(来自数据库,或“大量自定义对象”)。 在模型中,我创建了一个用于检索条目的接口:

        公共接口 IEntryHandler { IEnumerable GetEntries(); }

        在模型中,我有一个IEntryHandler 的实际实现 从缓存中读取条目并写入缓存的位置。

        公共类 EntryHandler : IEntryHandler { 公共 IEnumerable GetEntries() { // 检查对象是否在缓存中: List entries = [从缓存中获取条目] 如果(条目 == 空) { // 缓存中没有条目,所以我们从源中读取它们: entries = [从数据库中获取条目或'过多的自定义对象'] [将检索到的条目保存到缓存以供以后使用] } 返回条目; } }

        然后控制器会调用IEntryHandler:

        公共类 HomeController : 控制器 { 私人 IEntryHandler _entryHandler; // 默认构造函数,使用缓存和数据库/自定义对象 公共 HomeController() :这个(新的EntryHandler()) { } // 这个构造函数允许我们对控制器进行单元测试 // 通过编写一个实现 IEntryHandler 的测试类 // 但不影响数据库/自定义对象中的缓存或条目 公共 HomeController(IEntryHandler entryHandler) { _entryHandler = entryHandler; } // 此控制器操作将条目列表返回到视图: 公共行动结果索引() { 返回视图(_entryHandler.GetEntries()); } }

        这样就可以在不触及真正的缓存/数据库/自定义对象的情况下对控制器进行单元测试。

        【讨论】:

          【解决方案5】:

          我认为缓存应该以某种方式与模型相关。我认为控制器不应该更关心数据。控制器的职责是将数据(无论数据来自何处)映射到视图。

          也试着想想为什么需要缓存?你想保存处理,数据传输还是什么?这将帮助您了解缓存层的确切位置。

          【讨论】:

            【解决方案6】:

            这完全取决于手术的成本。如果您有复杂的查询,那么在控制器级别缓存数据可能是有意义的,这样查询就不会再次执行(直到缓存过期)。

            请记住,缓存是一个非常复杂的主题。您可以在许多不同的地方存储缓存:

            • Akamai / CDN 缓存
            • 浏览器缓存
            • 内存应用缓存
            • .NET 的缓存对象
            • 页面指令
            • 分布式缓存 (memcached)

            【讨论】:

              猜你喜欢
              • 2015-02-13
              • 2015-06-12
              • 2016-09-27
              • 1970-01-01
              • 2010-10-21
              • 1970-01-01
              • 2011-03-22
              • 1970-01-01
              • 2012-11-23
              相关资源
              最近更新 更多