zoukankan      html  css  js  c++  java
  • ASP.NET MVC 缓存控制

    缓存(cache)

    1.缓存是一种以空间换时间的技术, 比如, cpU的二级缓存,Windows的文件缓存。

    2.减少服务器的负荷,默认存放在内存里面,不过是可以修改的。

    3.缓存存在失效的情况。Asp.net 缓存主要分为页面缓存,数据源缓存,数据缓存。

    4. 页面缓存: %@OutPutCache Duration="15" VaryByParam="none" %

    属性说明

    VaryByParam是指页面根据使用 POST  GET 发送的名称/值对(参数)来更新缓存的内容,多个参数用分号隔开。如果不希望根据任何参数来改变缓存内容,请将值设置为 none。如果希望通过所有的参数值改变都更新缓存,请将属性设置为星号 (*) 

          例如: http://localhost:1165/16-4-3/WebForm1.aspx?p=1 
      则可以在WebForm1.aspx页面头部声明缓存:<%@ OutputCache Duration="60" VaryByParam="p" %> 

      以上代码设置页面缓存时间是60秒,并根据p参数的值来更新缓存,即p的值发生变化才更新缓存。 

      如果一直是WebForm1.aspx?p=1访问该页,则页面会缓存当前数据,当p=2时又会执行后台代码更新缓存内容。

      如果有多个参数时,如:http://localhost:1165/16-4-3/WebForm1.aspx?p=1&n=1

      可以这样声明:<%@ OutputCache Duration="60" VaryByParam="p;n" %>

    CacheProfile用于调用Web.config配置文件中设置的缓存时间。这是可选属性,默认值为空字符("")

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using MvcApplicationCacheSample.Models;
    using System.Web.UI;
    
    namespace MvcApplicationCacheSample.Controllers
    {
        public class HomeController : Controller
        {
            //
            // GET: /Home/
            [OutputCache(CacheProfile="employee")]
            public ActionResult Index()
            {
    
                Response.Cache.SetOmitVaryStar(true);
    
                ViewBag.CurrentTime = DateTime.Now.ToString();
    
    
                //这里目前作为演示,是直接硬编码,实际上可能是读取数据库的数据
                var employees = new[]{
                    new Employee(){ID=1,Name="ares",Gender="Male"}
                };
                return View(employees);
            }
    
        }
    }
    

      

    例如在Web.config中加入配置:

    <system.web>
    <caching>
      <outputCacheSettings>
        <outputCacheProfiles>
          <add name="employee" duration="10" enabled="true" location="ServerAndClient" varyByParam="none"/>
        </outputCacheProfiles>
      </outputCacheSettings>
    </caching>
    </system.web>
    

      页面中声明:

    <%@ OutputCache CacheProfile="CacheTest" VaryByParam="none"%>

      注意:包含在用户控件(.ascx 文件)中的 @ OutputCache 指令不支持此属性。在页中指定此属性时,属性值必须与 outputCacheSettings 节下面的 outputCacheProfiles 元素中的一个可用项的名称匹配。如果此名称与配置文件项不匹配,将引发异常。

      如果每个页面的缓存时间相同,则不需要每个页面设置,而是通过统一一个地方控制,这样就可以更好的统一控制所有页面的缓存时间。如果想改变缓存时间,只需要改一下web.config的配置信息即可,而不用每个页面去修改。

    VaryByControl通过用户控件文件中包含的服务器控件来改变缓存(值是控件ID,多控件用分号隔开)。

     ASP.NET 页和用户控件上使用 @ OutputCache 指令时,需要该属性或 VaryByParam 属性。

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="CacheWebApp._16_4_3.WebForm2" %>
    <%@ OutputCache Duration="60" VaryByParam="none" VaryByControl="DropDownList1" %>
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>根据控件页面缓存</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
             <%=DateTime.Now %>       
            <br>
        <asp:DropDownList ID="DropDownList1" runat="server">
            <asp:ListItem>beijing</asp:ListItem>
            <asp:ListItem>shanghai</asp:ListItem>
            <asp:ListItem>guangzhou</asp:ListItem>
            </asp:DropDownList>
            <asp:Button ID="Button1" runat="server" Text="提交" />
        </div>
        </form>
    </body>
    </html>
    

    以上代码设置缓存有效期是60秒,并且页面不随任何GETPOST参数改变(即使不使用VaryByParam属性,但是仍然需要在@ OutputControl指令中显式声明该属性)。如果用户控件中包含ID属性为“DropDownList1”的服务器控件(例如下拉框控件),那么缓存将根据该控件的变化来更新页面数据。

    VaryByHeader可以根据用户请求中所提供的一些Header信息不同而决定是否读取缓存。我们可以看到在每个请求中都会包含一些Header信息

    例如根据不同的语言,我们显然是有不同的版本的。或者根据用户浏览器不同,也可以缓存不同的版本。可以通过这样设置

    VaryByHeader=”Accept-Language,User-Agent”
    

    VaryByContentEncoding:一般设置为Accept-Encoding里面可能的Encoding名称,从上图也可以看出,Request里面是包含这个标头的。

    VaryByCustom:则是一个完全可以定制的设置,例如我们可能需要根据用户角色来决定不同的缓存版本,或者根据浏览器的一些小版本号来区分不同的缓存版本,我们可以这样设置:VaryByCustom=”Role,BrowserVersion”,这些名称是你自己定义的,光这样写当然是没有用的,我们还需要在Global.asax文件中,添加一个特殊的方法,来针对这种特殊的需求进行处理。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;
    using System.Web.Security;
    
    namespace MvcApplicationCacheSample
    {
        // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
        // visit http://go.microsoft.com/?LinkId=9394801
    
        public class MvcApplication : System.Web.HttpApplication
        {
            public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            {
                filters.Add(new HandleErrorAttribute());
            }
    
            public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
                routes.MapRoute(
                    "Default", // Route name
                    "{controller}/{action}/{id}", // URL with parameters
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
                );
    
            }
    
            protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
    
                RegisterGlobalFilters(GlobalFilters.Filters);
                RegisterRoutes(RouteTable.Routes);
            }
    
            public override string GetVaryByCustomString(HttpContext context, string custom)
            {
                switch(custom)
                {
                    case "Role":
                        {
                            return string.Join(",", Roles.GetRolesForUser());
                        }
                    case "BrowserVersion":
                        {
                            return context.Request.Browser.Type;
                        }
    
                    default:
                        break;
                }
    
                return string.Empty;
            }
        }
    }
    

      

    页面输出缓存API

       Response类的Cache属性用于获取页面缓存策略。该方式的核心是调用System.Web.HttpCachePolicy。该类主要包含用于设置缓存特定的HTTP标头的方法和用于控制ASP.NET页面输出缓存的方法。与.NET Framework 1.x中的HttpCachePolicy类相比,.NET Framework 2.0中的HttpCachePolicy类得到了扩充和发展。主要是增加了一些重要方法,例如,SetOmitVarStar方法等。由于HttpCachePolicy类方法众多,下面简要说明几个常用方法。

      SetExpires方法:用于设置缓存过期的绝对时间。它的参数是一个DataTime类的实例,表示过期的绝对时间。

     protectedvoid Page_Load(object sender, EventArgs e)
    {
    // 通过API设置缓存
    //相当于@OutputCache指令中的Duration属性
       Response.Cache.SetExpires(DateTime.Now.AddSeconds(10));
       Response.Cache.SetExpires(DateTime.Parse(
    "6:00:00PM"));
    }

      如上代码,第一行代码表示输出缓存时间是60秒,并且页面不随任何GETPOST参数改变,等同于“<%@ OutputCache Duration="60" VaryByParam="none" %>”。第二行代码设置缓存过期的绝对时间是当日下午6时整。

      SetLastModified方法:用于设置页面的Last-Modified HTTP标头。Last-Modified HTTP标头表示页面上次修改时间,缓存将依靠它来进行计时。如果违反了缓存限制层次结构,此方法将失败。该方法的参数是一个DataTime类的实例。

      SetSlidingExpiration方法:该方法将缓存过期从绝对时间设置为可调时间。其参数是一个布尔值。当参数为true时,Cache-Control HTTP标头将随每个响应而更新。此过期模式与相对于当前时间将过期标头添加到所有输出集的IIS配置选项相同。当参数为False时,将保留该设置,且任何启用可调整过期的尝试都将静态失败。此方法不直接映射到HTTP标头。它由后续模块或辅助请求来设置源服务器缓存策略。

      SetOmitVaryStar方法:ASP.NET 2.0新增的方法。用于指定在按参数进行区分时,响应是否应该包含vary:*标头。方法参数是一个布尔值,若要指示HttpCachePolicy不对其VaryByHeaders属性使用*值,则为true;否则为false

      SetCacheability方法:用于设置页面的Cache-Control HTTP标头。该标头用于控制在网络上缓存文档的方式。该方法有两种重载方式,所不同的是参数。一种重载方法的参数是HttpCacheability枚举值,包括NoCachePrivatePublicServerServerAndNoCacheServerAndPrivate(有关这些枚举值的定义,可参考MSDN)。另一种方法的参数有两个,一个参数是HttpCacheability枚举值,另一个参数是字符串,表示添加到标头的缓存控制扩展。需要注意的是,仅当与PrivateNoCache指令一起使用时,字段扩展名才有效。如果组合不兼容的指令和扩展,则此方法将引发无效参数异常。

    1。整页缓存

    [OutputCache(Duration = 3600, Location = OutputCacheLocation.Server, VaryByParam = "none")]
    public ActionResult Index()
    {
          //Do something.
    }
    

      此外还可以在View窗口声明

    <%@ OutputCache Duration="#ofseconds"
       Location="Any | Client | Downstream | Server | None | 
         ServerAndClient "
       Shared="True | False"
       VaryByControl="controlname"
       VaryByCustom="browser | customstring"
       VaryByHeader="headers"
       VaryByParam="parametername"
       VaryByContentEncoding="encodings"
       CacheProfile="cache profile name | ''"
       NoStore="true | false"
       SqlDependency="database/table name pair | CommandNotification"
    %>
    

    2 数据源缓存

    <asp:ObjectDataSource EnableCaching="true" CacheDuration="20" ID="ObjectDataSource1" runat="server" SelectMethod="GetList" TypeName="BLL.Classes"></asp:ObjectDataSource>
    

    3:自定义缓存

    List<MODEL.Classes> list=null;
    
                if (Cache["myDog"] == null)
                {
                    Cache["myDog"] = new Dog() { StrName = "小瑞瑞", StrType = "柯基犬" };
                    Response.Write("保存了一只狗狗");
                    //查询数据库 存入缓存
                    list = new BLL.Classes().GetList();
                    Cache["list"] =  list;
                }
                else
                {
                    Dog myDog = Cache["myDog"] as Dog;
                    Response.Write("myDog="+myDog.StrName);
                    //从缓存里获取数据
                    list = Cache["list"] as List<MODEL.Classes>;
                }
               myDog, list 就可以使用了
    

    4.文件依赖项自定义缓存(新建一个文件 这里是txt)

    List<MODEL.Classes> list=null;
    
                if (Cache["list"] == null)
                {
                    //查询数据库 存入缓存
                    list = new BLL.Classes().GetList();
                    //设置绝对过期时间
                    //Cache.Insert("list", list, null, DateTime.Now.AddSeconds(20),System.Web.Caching.Cache.NoSlidingExpiration);
                    //设置滑动过期时间
                    //Cache.Insert("list", list, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(10000));
                    //带 文件缓存依赖
                    string strPath = Server.MapPath("1.txt");
                    //文件缓存依赖项
                    System.Web.Caching.CacheDependency fileDep = new System.Web.Caching.CacheDependency(strPath);
                    //创建带文件依赖的缓存 键值项
                    Cache.Insert("list", list, fileDep, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration);
    
                    Response.Write("依赖文件被修改了,又重新读取数据列表存入缓存中了~~!");
                    
                }
                else
                {
                    //从缓存里获取数据
                    list = Cache["list"] as List<MODEL.Classes>;
                }
                使用缓存list
    

      

     一、MVC缓存问题:

    在 ASP.NET MVC 3 中如果使用了 OutputCache,一定要在 Action 中添加下面的代码,切记!

    Response.Cache.SetOmitVaryStar(true);

    这是一个伴随ASP.NET从1.0到4.0的OutputCache Bug,ASP.NET MVC 3 是基于 ASP.NET 4.0 的,所以也躲不过。

    问题演示

    下面先来体验一下不加 Response.Cache.SetOmitVaryStar(true); 的情况。

    示例Action代码:

    [OutputCache(Duration = 120)]
    public ActionResult SiteHome(int? pageIndex)
    {
        ...
    }

    注:OutputCache.Location的默认值是OutputCacheLocation.Any(服务端、客户端、代理服务器端等都进行缓存)

    第一次请求:

    第二次请求(F5刷新浏览器):

    第三次请求(F5刷新浏览器):

    接着第四次请求会返回304,第五次请求又返回200。。。

    再体验一下加 Response.Cache.SetOmitVaryStar(true); 的情况。

    [OutputCache(Duration = 120)]
    public ActionResult SiteHome(int? pageIndex)
    {
        Response.Cache.SetOmitVaryStar(true);
        ...
    }

    第一次请求:

    第二次请求(F5刷新浏览器):

    第三次请求(F5刷新浏览器):

    注:只要在缓存有效期内,服务器一直返回304。

    问题分析

    1. 200与304的区别

    当返回状态码是200时,服务器端会将当前请求的整个页面全部发送给客户端(消耗下行带宽)。

    当返回状态码是304时,由于客户端浏览器提供的 Last-Modified 时间在服务器端的缓存有效期内,服务器端只发送这个状态码,不发送页面的任何内容(几乎不消耗下行带宽),浏览器直接从本地缓存中获取内容。

    所以,304的好处就是节约带宽,响应速度更快。

    2. 对服务端缓存的影响

    加不加 Response.Cache.SetOmitVaryStar(true),服务端的缓存情况都是一样的。只是不加 SetOmitVaryStar(true) 时,对于同一个客户端浏览器,每隔一次请求,服务器端就不管客户端浏览器的缓存,重新发送页面内容,但是只要在缓存有效期内,内容还是从服务器端缓存中读取。

    问题危害

    ASP.NET 缓存的这个诡异行为,让你在不知不觉中浪费了带宽资源。

    感想

    用 ASP.NET 开发多年,这个伴随 ASP.NET 从 1.0 到 4.0 的 OutputCache Bug 自己竟然在去年才发现。之前测试时第一次请求后按F5看返回304就以为没问题,而问题恰恰就在下一下F5,偶尔多按一下F5出现200也没特别留意。由此可见,细心对程序员来说是多么重要,很多bug、很多性能问题往往不是水平不够,而是不够细心。

    优秀的程序员都是细心的人,不仅在写代码的时候细心,在生活中也同样细心。别看他木讷的样子,你对他所做的一切,他都会细心地观察到、体会到。做细心的程序员,珍惜细心的程序员!

    二、ASP.NET MVC Action Filter - 缓存与压缩

    缓存在开发高扩充性WEB程序的时候扮演着很重要的角色.我们可以将HTTP请求在一个定义的时间内缓存在用户的浏览器中,如果用户在定义的时间内请求同一个URL,那么用户的请求将会从用户浏览器的缓存中加载,而不是从服务器.你可以在ASP.NET MVC应用程序中使用下面的Action Filter来实现同样的事情:

    using System;
    using System.Web;
    using System.Web.Mvc;
    
    public class CacheFilterAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// Gets or sets the cache duration in seconds. The default is 10 seconds.
        /// </summary>
        /// <value>The cache duration in seconds.</value>
        public int Duration
        {
            get;
            set;
        }
    
        public CacheFilterAttribute()
        {
            Duration = 10;
        }
    
        public override void OnActionExecuted(FilterExecutedContext filterContext)
        {
            if (Duration <= 0) return;
    
            HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
            TimeSpan cacheDuration = TimeSpan.FromSeconds(Duration);
    
            cache.SetCacheability(HttpCacheability.Public);
            cache.SetExpires(DateTime.Now.Add(cacheDuration));
            cache.SetMaxAge(cacheDuration);
            cache.AppendCacheExtension("must-revalidate, proxy-revalidate");
        }
    }

    你可以好像下面一样在你的Controller Action 方法中使用这个Filter :

    
    
    [CacheFilter(Duration = 60)]
    public void Category(string name, int? page)

    下面是在firebug中当 缓存Filter 没有应用的时候的截图 :

    NoCache

    下面的截图是应用了 Cache Filter 时候的截图 :

    Cache

    另外一个很重要的事情就是压缩.现在的浏览器都可以接收压缩后的内容,这可以节省大量的带宽.你可以在你的ASP.NET MVC 程序中应用下面的Action Filter 来压缩你的Response :

    
    
    using System.Web;
    using System.Web.Mvc;
    
    public class CompressFilter : ActionFilterAttribute
    {
        public override void OnActionExecuting(FilterExecutingContext filterContext)
        {
            HttpRequestBase request = filterContext.HttpContext.Request;
    
            string acceptEncoding = request.Headers["Accept-Encoding"];
    
            if (string.IsNullOrEmpty(acceptEncoding)) return;
    
            acceptEncoding = acceptEncoding.ToUpperInvariant();
    
            HttpResponseBase response = filterContext.HttpContext.Response;
    
            if (acceptEncoding.Contains("GZIP"))
            {
                response.AppendHeader("Content-encoding", "gzip");
                response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
            }
            else if (acceptEncoding.Contains("DEFLATE"))
            {
                response.AppendHeader("Content-encoding", "deflate");
                response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
            }
        }
    }

    然后将这个Filter应用到你的Controller Action 中 :

    [CompressFilter]
    public void Category(string name, int? page)

    下面是没有应用压缩的时候的截图 :

    Uncompressed

    下面的截图是应用了压缩Filter后的情形 :

    Compressed

    你当然也可以将这两个Filter都应用到同一个Action方法上,就好像下面所示 :

    
    
    [CompressFilter(Order = 1)]
    [CacheFilter(Duration = 60, Order = 2)]
    public void Category(string name, int? page)

    下面是截图 :

    Both

    Enjoy!!!

    下载源码Source.zip

  • 相关阅读:
    dapper+linq+json+ztree构建树
    ubuntu,从一个新用户,要转到新用户的命令行操作
    OC本学习笔记Foundatio框架集
    无法Debug SQL: Unable to start T-SQL Debugging. Could not attach to SQL Server process on
    Struts2 + uploadify 多文件上传完整的例子!
    How use Instruments and display the console in Command Lines applications
    Android ActionBar详解(二):ActionBar实现Tabs标签以及下拉导航
    Android ActionBar详解(一):ActionBar概述及其创建
    Android Fragment详解(六):Fragement示例
    Android Fragment详解(五):Fragment与Activity通讯
  • 原文地址:https://www.cnblogs.com/haiyabtx/p/2776462.html
Copyright © 2011-2022 走看看