【问题标题】:To Cache or not to cache? And how to cache it on a base controller in asp.net mvc?缓存还是不缓存?以及如何将其缓存在 asp.net mvc 的基本控制器上?
【发布时间】:2012-03-24 05:37:55
【问题描述】:

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

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

所以我不知道该怎么办。

我的几行代码就是这样做的。

  1. 查找用户名并将其显示给用户。
  2. 找到用户计划并将其显示出来。

所以我需要用户名来找出他们的 GUID,这样我就可以找出他们注册的计划。

所以我不知道如何缓存它,但不向所有人公开。有没有办法只为这个用户缓存?

引用 Asp.net mvc framework unleasehd pg 330

不要缓存私人数据

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

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

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

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

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

一般来说,添加 OutputCache 和 授权属性相同 控制器动作打开一个安全 洞。避免这样做:

【问题讨论】:

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


    【解决方案1】:

    回答是否应该缓存某些内容的最佳方法是确定它是否真的影响了您网站的性能。使用实际指标。不要猜测。如果它没有伤害任何东西并且一切似乎都有反应,那么我会说在需要出现之前做其他事情。 “Permature 优化是万恶之源”已经说过一两次了 :)

    如果您确实选择缓存数据,我不确定您的意思是每个人都可以看到它?如果您指的是 ASP.NET 缓存框架 (HttpContext.Current.Cache),那么它存在于您的服务器内存中并且是完全易失的(如果内存压力遇到它,它随时会被清除)。因此,请确保牢记这一点并始终检查 null。要使用它,您可以简单地使用 Cache.Insert(),它有几个重载来自定义您的缓存首选项。

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

    如果安全性对您来说是一个大问题,那么您绝对应该阅读更多有关 XSS 和其他常见 HTTP 安全问题的信息。 (应该是:)

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

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

    我引用 Steve Sanderson(Pro ASP.NET MVC Framework 的作者)的以下内容

    更新:自 Beta 版发布以来, [Authorize] 过滤器现在做了一些 巧妙的诡计合作 ASP.NET 输出缓存。具体来说, 它使用 HttpCachePolicy.AddValidationCallback(), 以便它可以拦截未来的缓存 命中并告诉 ASP.NET 输出缓存 [授权]时不使用缓存 会拒绝请求。这解决了 ASP.NET 输出缓存的问题 绕过 [Authorize] 过滤器。如果 你要自己写 授权过滤器,请务必 从 AuthorizeAttribute 派生它所以 你可以继承这个有用的行为。

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

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

    【讨论】:

    • 可能值得注意的是,输出缓存仅适用于(几乎)静态数据,用户 GUID 和用户计划听起来不像(因为它们也是特定于请求的)。
    • 是的,它们是特定于用户的,但我试图找出是否有办法为该特定用户缓存它。因此,不需要对同一事物进行一百万次查询。
    • 首先,如果您遵循我的 BaseViewModel 概念,您只需在需要时加载它(即不适用于 ajax 请求)。其次,如果您仍然担心对许多请求进行处理,您可以将数据存储在特定于客户端的 Session 对象中。但是,在经历 Matt Hidinger 正确提到的长度之前,请先进行测量。
    【解决方案2】:

    您的控制器类只有一个从动作请求到视图呈现的生命周期。你真的需要缓存这些数据吗?只需在模型对象中公开数据。这些查询听起来不够复杂,除此之外,大多数 RDBMS 供应商倾向于自己进行大量查询缓存。

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

    ASP.NET MVC中的流程大致是

    • 请求网址
    • 控制器被调用
    • 动作被调用
    • 操作调用数据模型(用户名/用户计划)
    • Action 设置视图模型中的数据
    • Action 使用视图模型中的数据调用所需的视图
    • 视图已渲染。

    在视图模型上设置数据已经是“私有的”,所以我不确定缓存的需求来自哪里。也许我误解了这个问题?

    编辑

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

    一个好的做法是传入类型化的 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 的构造函数中实例化您的用户 guid 和用户计划,并且只会在实际实例化 BaseViewDataModel 子类的操作中调用它。

    而且您的视图是类型安全的,这极大地提高了生产力,因为我们输入了我们现在可以实际调用的视图

    <%= this.Model.HelpText %>
    

    在帮助视图中。

    【讨论】:

    • 将数据传递到母版页,而无需将此代码放入控制器中的每个 actionView 中。我必须制作自己的 baseController。这就是我的疑问所在。因此,在我的基本控制器中初始化时,我有一个获取 userPlan 的查询。每次。我试图显示此代码的页面是所有 ajax,它们都进入视图并具有 ajax 选项卡。每次您单击一个选项卡时,我都会重新点击该查询。因此,如果不进行缓存,此方法将无缘无故地继续访问数据库。如果我的ajax请求去partialView返回数据段,我什至没有看到......
    • 导致此代码也被命中。可能是用户在该页面上执行了 10 次操作,并且该查询被点击了 10 次。现在想想 50 次? 100 次。因此,如果我能得到它,它只需要真正执行一次此查询并缓存它,那就太好了。查看您的生命周期流程,此代码将在 Url 和 Controller 中间的某个位置调用(基本上只要母版页被调用)。
    • 我更新了我的答案,以更好地反映我来自哪里。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-24
    • 1970-01-01
    • 1970-01-01
    • 2011-06-15
    • 1970-01-01
    • 2017-06-14
    • 2018-03-09
    相关资源
    最近更新 更多