要缓存还是不缓存?以及如何在asp.net mvc的基础控制器上缓存它?

时间:2009-10-01 21:03:40

标签: .net asp.net asp.net-mvc

我正在创建自己的基本控制器,因为我想将一些数据传递给母版页。现在,因为这就像将此代码添加到该控制器中的每个视图一样,它每次都会运行。

当它第一次加载时我认为它至少击中了我的代码两次。所以我在考虑缓存它。但在我的书中,它表示不会缓存私人数据,因为每个人都会看到它。

所以我不知道该怎么做。

我的几行代码的作用是什么。

  1. 查找用户名并将其显示给用户。
  2. 查找用户计划并显示该计划。
  3. 所以我需要userName来找出他们的GUID,这样我才能知道他们注册了什么计划。

    所以我不知道如何缓存它,但不将它暴露给每个人。有没有让它只为这个用户缓存?

    引用Asp.net mvc框架unleasehd第330页

      

    不要缓存私人数据

         

    缓存包含私有的页面   用户数据非常危险。什么时候   一个页面缓存在服务器上,   同一页面将提供给所有用户。所以,   如果你缓存一个显示的页面   用户信用卡号,每个人都可以   看到信用卡号码(不是   好!)。

         

    为所有用户缓存相同的页面   即使您需要授权。   想象一下,例如,你创造   一个金融服务网站和   网站包含显示的页面   所有用户的投资。这页纸   显示a的金额   用户投资了一组股票,   债券和共同基金。

         

    因为此信息是私密的,   您需要用户之前登录   看到这个页面。换句话说,每个   用户必须在之前获得授权   用户可以查看该页面。

         

    提高性能   金融服务页面,您决定   启用页面缓存。你添加   OutputCache属性为   返回的控制器动作   页。

         

    不要那样做!如果你缓存了   返回的控制器动作   金融服务页面,私人   第一人称的财务数据   请求页面将被共享   每一个后来的访客   应用

         

    一般情况下,添加OutputCache和   授权属性相同   控制器操作打开安全性   洞。避免这样做:

2 个答案:

答案 0 :(得分:2)

回答是否应缓存某些内容的最佳方法是确定它是否实际影响了您网站的效果。使用实际指标。不要猜。如果它没有伤害任何东西,而且一切看起来都很敏感,那么我会说在其他方面工作直到需要出现。 “过早的优化是所有邪恶的根源”已经说了一两次:)

如果你确实选择缓存数据,我不确定你的意思是每个人都可以看到它?如果您的意思是ASP.NET缓存框架(HttpContext.Current.Cache),那么它将存在于您的服务器内存中并且完全不稳定(如果内存压力达到它,它将随时被删除)。因此,请务必记住这一点并始终检查是否为空。要使用它,您只需使用Cache.Insert()并且它有一些重载来自定义您的缓存首选项。

现在,如果您正在谈论使用浏览器cookie缓存某些内容,这是另一个故事。 Cookie确实存储在浏览器中,除非你为cookie指定HttpOnly,它可以通过javascript读取(如果你有某个XSS漏洞,这只是一个问题 - 因为恶意用户可以使用javascript来“回家” “用户的私人cookie数据。”因此,除非绝对必要,否则不要将任何内容私有放入cookie中,如果这样做,则应指定HttpOnly并采取适当措施保护您的用户。

如果安全性是您最关心的问题,那么您肯定应该阅读有关XSS和其他常见HTTP安全问题的更多信息。 (它应该是:)

更新以解决有关输出缓存的问题编辑:

好的,所以你特意指的是输出缓存。事实上,这本书提到了一个安全漏洞,我相信在MVC 1发布之前已经修补了。当这两个属性结合使用时,Authorize属性应足够智能以正确处理输出缓存。也许这本书是在预览版中编写的,不再相关。

我引用了Steve Sanderson(Pro ASP.NET MVC框架的作者)

的以下内容
  

更新:自Beta发布以来,   [授权]过滤器现在做了一些   聪明的诡计与合作   ASP.NET输出缓存。特别,   它使用注册代理   HttpCachePolicy.AddValidationCallback()   这样它就可以拦截未来的缓存   点击并告诉ASP.NET输出缓存   [授权]时不使用缓存   会拒绝这个请求。这解决了   ASP.NET输出缓存的问题   绕过[授权]过滤器。如果   你要写自己的   授权过滤器,一定要   从AuthorizeAttribute派生出来   你可以继承这种有用的行为。

     

请注意,这不会阻止ASP.NET   输出缓存绕过任何一个   你的其他动作过滤器,它   不添加任何部分支持   缓存。如果这对你来说是个问题   然后考虑使用   [ActionOutputCache](下面)改为。

阅读他的文章(和他的书,就此而言)是值得的: http://blog.codeville.net/2008/10/15/partial-output-caching-in-aspnet-mvc/

答案 1 :(得分:1)

您的Controller类只有一个从action-request延伸到view-rendered的生命周期。你真的需要缓存这些数据吗?只需公开Model对象中的数据即可。这些查询听起来不够复杂,而且大多数RDBMS供应商都倾向于自己进行大量的查询缓存。

HTTP是一种无状态协议,这意味着在请求之后,您的Web服务器会忘记所述请求的所有内容。为了规避这种无状态,asp.net提供了Application和Session对象。应用程序全局可用于所有请求,并且会话绑定到单个IP。将任何数据放在那里通常是最后的手段或部分方案来缓存真正具有大量加载时间的数据。

ASP.NET MVC中的流程大致是

  • 请求网址
  • 调用控制器
  • 行动称为
  • 操作调用数据模型(用户名/用户计划)
  • 操作设置viewmodel中的数据
  • Action使用viewmodel
  • 中的数据调用所需的视图
  • 查看视图。

在viewmodel上设置数据已经是“私有”所以我不确定缓存需求来自何处。也许我误解了这个问题?

修改

好的,首先请原谅我,如果我的帖子有点冒昧。我认为你的代码根本不需要进入基础构造函数的构造函数。毕竟,您不会将控制器传递给视图。

一个好的做法是传入类型化的ViewModel。说这是您在site.master中的定义

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyNS.BaseViewDataModel>" %>

这个定义是说你的帮助页面查看:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyNS.HelpViewDataModel>" %>

然后,您可以创建一个BaseViewDataModel

namespace MyNS
{
    public class BaseViewDataModel

和你的HelpViewDataModel

namespace MyNS
{
    public class HelpViewDataModel : BaseViewDataModel 
    {

然后在你的帮助控制器的适当行动中

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index()
{
    var viewDataModel = new HelpViewDataModel ();
            viewDataModel.HelpText = "something";
            ..
            ..
    return View(viewDataModel);
}

您现在可以在BaseViewDataModel的构造函数中实例化您的用户指南和用户计划,并且只会为实际实例化BaseViewDataModel子类的操作调用它。

您的观点是类型安全的,因为我们输入了我们现在可以实际调用的视图

,这是巨大的生产力增益
<%= this.Model.HelpText %>

在帮助视图中。