码迷,mamicode.com
首页 > Web开发 > 详细

Asp.Net 基础知识回顾_Cache

时间:2018-03-27 01:49:35      阅读:265      评论:0      收藏:0      [点我收藏+]

标签:层次结构   数据   代理服务   缓存机制   ons   知识   lca   布尔   版本   

一、传统缓存方式

比如将可重复利用的东西放到Application或是Session中去保存。

 Session["Count"] = 100;

 Application["Count"] = 100;

二、页面输出缓存

页面输出缓存是最为简单的缓存机制,该机制将整个ASP.NET页面内容保存在服务器内存中。当用户请求该页面时,系统从内存中输出相关数据,直到缓存数据过期。在这个过程中,缓存内容直接发送给用户,而不必再次经过页面处理生命周期。通常情况下,页面输出缓存对于那些包含不需要经常修改内容,需要大量处理才能编译完成的页面特别有用。需要注意的是,页面输出缓存是将页面全部内容都保存在内存中,并用于完成客户端请求。

设置页面输出缓存可以使用以下两种方式:一种是使用@OutputCache指令,另一种是使用页面输出缓存API。页面输出缓存API主要是指HttpCachePolicy类。

@ OutputCache以声明的方式控制 ASP.NET 页或页中包含的用户控件的输出缓存策略。

语法如下:

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

Duration

页或用户控件进行缓存的时间(以秒计)。在页或用户控件上设置该属性为来自对象的 HTTP 响应建立了一个过期策略,并将自动缓存页或用户控件输出。

Location

用于指定输出缓存项的位置。其属性值是OutputCacheLocation枚举值,它们是Any、Client、Downstream、None、Server和ServerAndClient。默认值是Any,表示输出缓存可用于所有请求,包括客户端浏览器、代理服务器或处理请求的服务器上。需要注意的是,包含在用户控件中的@OutputCache指令不支持此属性。

Shared

一个布尔值,确定用户控件输出是否可以由多个页共享。默认值为 false。

NoStore

该属性定义一个布尔值,用于决定是否阻止敏感信息的二级存储。需要注意的是,包含在用户控件中的
@OutputCache指令不支持此属性。

SqlDependency

    提供了这样一种能力:当被监测的数据库中的数据发生变化时,SqlDependency会自动触发OnChange事件来通知应用程序,从而达到让系统自动更新数据(或缓存)的目的。

VaryByControl

该属性使用一个分号分隔的字符串列表,来更改用户控件的输出缓存。这些字符串代表在用户控件中声明的ASP.NET服务器控件的ID属性值。除非已经包含了VaryByParam属性,否则在@ OutputCache指令中,该属性是必需的。

VaryByCustom

用于自定义输出缓存要求的任意文本。如果赋予该属性值是browser,缓存将随浏览器名称和主要版本信息的不同而异。如果输入了自定义字符串,则必须在应用程序的Global.asax文件中重写HttpApplication.GetVaryByCustomString方法。

VaryByHeader

该属性中包含由分号分隔的HTTP标头列表,用于使输出缓存发生变化。当将该属性设为多标头时,对于每个指定的标头,输出缓存都包含一个请求文档的不同版本。VaryByHeader属性在所有HTTP 1.1缓存中启用缓存项,而不仅限于ASP.NET缓存。用户控件中的@ OutputCache指令不支持此属性。

三、页面输出缓存API

Response类的Cache属性用于获取页面缓存策略,Cache属性的核心是调用System.Web.HttpCachePolicy。主要用于设置缓存特定的HTTP标头的方法和用于控制ASP.NET页面输出缓存的方法。由于HttpCachePolicy类方法众多,下面简要说明几个常用方法。

SetExpires

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

SetLastModified

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

SetSlidingExpiration 

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

SetCacheability

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

Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));

Response.Cache.SetExpires(DateTime.Parse("6:00:00PM"));

Response类的Cache属性用于获取页面缓存策略。该属性的数据类型是HttpCachePolicy。可通过调用Response.Cache来获取HttpCachePolicy实例,进而实现对于当前页面输出缓存的设置。如上代码所示,第一行代码表示输出缓存时间是60秒,并且页面不随任何GET或POST参数改变,等同于“<%@ OutputCache Duration="60" VaryByParam="none" %>”。第二行代码设置缓存过期的绝对时间是当日下午6时整。

四、页面部分缓存

有时缓存整个页面是不现实的,因为页的某些部分可能在每次请求时都需要变化。在这些情况下,只能缓存页的一部分。顾名思义,页面部分缓存是将页面部分内容保存在内存中以便响应用户请求,而页面其他部分内容则为动态内容。在页面中经常存在某些部分固定不变(如导航栏,页面右侧的排行榜等信息),而其他内容则需要根据用户请求的不同动态生成。所以我们可以将固定部分的内容缓存在服务器内存中,以减少服务器查询数据时间。

页面部分缓存也称为控件缓存,这种方式允许将需要缓存的信息包含在一个用户控件内。然后,将该用户控件标记为可缓存的,以此来缓存页面输出的部分内容。这种方式允许缓存页面中的特定内容,而不缓存整个页面。例如,如果要创建一个显示大量动态内容(如股票信息)的页,其中有些部分为静态内容(如每周总结),这时可以将静态部分放在用户控件中,并允许缓存这些内容。

页面部分缓存示例如下: 

CacheControl.ascx的页头代码中添加声明语句:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="CacheControl.ascx.cs" Inherits="CacheControl" %>

  <%@ OutputCache Duration="60" VaryByParam="none" %>

<%=DateTime.Now %>  

调用该控件的页面代码:

 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="CacheDemo.aspx.cs"%>
<%@ Register src="CacheControl.ascx" tagname="CacheControl" tagprefix="uc" %>
<head runat="server">
    <title>CacheDemo</title>
</head>
<body>
    <form id="form1" runat="server">
    页面的时间:<%=DateTime.Now %> <br/>
  控件的时间:<uc:CacheControl ID="CacheControl" runat="server" /><br/>
    </form>
</body> 
</html>

当刷新页面时,“页面的时间”每次刷新都变化,而“控件的时间”的数据却是60秒才变化一次。说明对页面的“局部”控件实现了缓存,而页面其它部分不受影响。

五、 应用程序数据缓存

应用程序数据缓存提供了一种编程方式,可通过键/值对将任意数据存储在内存中。使用应用程序缓存与使用应用程序状态类似。但是,与应用程序状态不同的是,应用程序数据缓存中的数据是易失的,即数据并不是在整个应用程序生命周期中都存储在内存中。应用程序数据缓存的优点是由ASP.NET管理缓存,它会在项过期、无效,或内存不足时移除缓存中的项。还可以配置应用程序缓存,以便在移除项时通知应用程序。

如下所示插入一个字符串进缓存:

Cache["name"]="CacheDemo";

这个存储的字串值可以像这样得到:

if (Cache["name"] != null)
{
string name = Cache["name"].ToString();
}

六、 缓存依赖

前文的几种方式都可以实现数据缓存功能,但问题是数据有时候是在变化的。这样用户可能在缓存期间查询的数据就是过期的数据,从而导致数据的不一致。那有没有办法在数据变化时,系统能自动更新缓存中的数据,从而让用户得到实时有效的数据。

.NET已经为我们提供了这样一种非常好的解决方法:SqlCacheDependency数据库缓存依赖。下面就让我们看一下如何实现数据库缓存依赖功能:

1. 配置SqlCacheDependency 

修改web.config,让项目启用SqlCacheDependency。

<?xml version="1.0"?>
<configuration>
    <appSettings/>
    <connectionStrings>
        <add name="strcodematic" connectionString="data source=dbserver;initial catalog=codematic;user id=sa;password=sa"  providerName="System.Data.SqlClient" />
    </connectionStrings>
    <system.web>
        <caching>
            <sqlCacheDependency enabled="true" pollTime="6000">
                <databases>
 <add name="codematic" connectionStringName="strcodematic" />
                </databases>
            </sqlCacheDependency>         
        </caching>
      <compilation debug="true">
        </compilation>     
        <authentication mode="Windows"/>    
    </system.web>
</configuration> 

注意:在<databases>节的<add name="codematic" connectionStringName="strcodematic" />中的name属性值必须和第三步的Page_Load代码中System.Web.Caching.SqlCacheDependency("codematic", "P_Product"); 中的第一个参数(数据库名称)相一致。

这里的connectionStringName指定了在<connectionStrings>中添加的某一个连接字符串。name则是为该SqlCacheDependency起的名字,这个名字将在第三步中用到。

SqlCacheDependency类会自动完成对此配置节信息的读取,以建立和数据库之间的联系。

2.启用缓存依赖

如果要启用SqlCacheDependency,则需要以命令行的方式执行。

aspnet_regsql.exe工具位于Windows\\Microsoft.NET\\Framework\\[版本]文件夹中。

aspnet_regsql -C "data source=.;initial catalog=codematic;user id=sa;password=123456" -ed -et -t "BookInfo"

参数-C后面的字符串是连接字符串(请替换成自己所需要的值),参数-t后面的字符串是数据表的名字。

 运行结果如图所示:

技术分享图片

命令执行后,在指定的数据库中会多出一个AspNet_SqlCacheTablesForChangeNotification表。

要使得7.0或者2000版本以上的SQLServer支持SqlCacheDependency特性,需要对数据库服务器执行相关的配置。

有两种方法配置SQLServer:

一 使用aspnet_regsql命令行工具。

二 使用SqlCacheDependencyAdmin类。(msdn看到的,没用过

例如:

aspnet_regsql -S "server" -E -d "database" –ed

或者

aspnet_regsql -S "server" -E -d "database" -et -t "table"

如果是Sql验证的话要把-E换成,-U (用户名),-P (密码)

以下是该工具的命令参数说明:

-? 显示该工具的帮助功能;

-S 后接的参数为数据库服务器的名称或者IP地址;

-U 后接的参数为数据库的登陆用户名;

-P 后接的参数为数据库的登陆密码;

-E 使用当前登录用户的 Windows 集成认证进行身份验证;

-d 后接参数为对哪一个数据库采用SqlCacheDependency功能;

-C 连接数据库的连接字符串。如果您指定服务器(-S)和登录(-U和-P,或 -E)信息,则此选项不是必需的,因为连接字符串已经包含这些信息;
-t 后接参数为对哪一个表采用SqlCacheDependency功能;
-ed 允许对数据库使用SqlCacheDependency功能;
-dd 禁止对数据库采用SqlCacheDependency功能;
-et 允许对数据表采用SqlCacheDependency功能;
-dt 禁止对数据表采用SqlCacheDependency功能;
-lt 列出当前数据库中有哪些表已经采用sqlcachedependency功能;

3.0使用SqlCacheDependency 

在代码中使用缓存,并为其设置SqlCacheDependency依赖:

 

/// <summary>
/// 获取当前应用程序指定CacheKey的Cache对象值
/// </summary>
/// <param name="CacheKey">索引键值</param>
/// <returns>返回缓存对象</returns>
public static object GetCache(string CacheKey)
{
    System.Web.Caching.Cache objCache = HttpRuntime.Cache;
    return objCache[CacheKey];
}
/// <summary>
/// 设置以缓存依赖的方式缓存数据
/// </summary>
/// <param name="CacheKey">索引键值</param>
/// <param name="objObject">缓存对象</param>
/// <param name="cacheDepen">依赖对象</param>
public static void SetCache(string CacheKey, object objObject, System.Web.Caching.CacheDependency dep)
{
    System.Web.Caching.Cache objCache = HttpRuntime.Cache;
    objCache.Insert(
        CacheKey,
        objObject,
        dep,
        System.Web.Caching.Cache.NoAbsoluteExpiration,//从不过期
        System.Web.Caching.Cache.NoSlidingExpiration,//禁用可调过期
        System.Web.Caching.CacheItemPriority.Default,
        null);
}
protected void Page_Load(object sender, EventArgs e)
{
    string CacheKey = "cachetest";
    object objModel = GetCache(CacheKey);//从缓存中获取
    if (objModel == null)//缓存里没有
    {
        objModel = GetData();//把当前时间进行缓存
        if (objModel != null)
        {
            //依赖数据库codematic中的P_Product表变化 来更新缓存
            System.Web.Caching.SqlCacheDependency dep = new System.Web.Caching.SqlCacheDependency("CodeMatic", "P_Product");
            SetCache(CacheKey, objModel, dep);//写入缓存
        }
    } 
    GridView1.DataSource = (DataSet)objModel;
    GridView1.DataBind();
}

从以上代码可以看出,和文件依赖基本相同,只是在存放缓存SetCache时存入的依赖对象不同。这里用的是SqlCacheDependency。

其中,创建SqlCacheDependency的构造方法:

public SqlCacheDependency (string databaseEntryName,string tableName)
//databaseEntryName:是在Web.config文件的caching节的sqlCacheDependency的databases元素中定义的数据库的名称。 
//tableName:与SqlCacheDependency关联的数据库表的名称。
//这样,只有当P_Product表的内容发生变化时,查询操作才会重新查询数据更新缓存的内容,可以大大减少数据库的重复查询和提高系统的性能和运行效率。

七、缓存管理类

首先,缓存管理类外部代码定义了各种过期时间的常量,主要用于方便设定缓存的过期时间

/// <summary>
    /// 全站缓存类
    /// </summary>
    public sealed class SiteCache
    {
        // 一天
        public const int DayFactor = 17280;
        // 一小时
        public const int HourFactor = 720;
        // 一分钟
        public const int MinuteFactor = 12; 
        // 一秒
        public const double SecondFactor = 0.2;

        private static int factor = 5;
        /// <summary>
        /// 时间因子
        /// </summary>
        public static int Factor
        {
            get { return factor; }
            set { factor = value; }
        }

 public static Cache CurrentCache {
            get {
                return HttpRuntime.Cache;
            }
        }
        }
//Clear方法用于移除所有存储在内存当中的缓存,代码中cacheEnum变量通过GetEnumerator方法获得所有缓存列表,再根据缓存列表来移除缓存。
        public static void Clear()
        {
            //获取缓存中的键设置及其值的字典枚举数
            IDictionaryEnumerator cacheEnum = siteCache.GetEnumerator();
            ArrayList al = new ArrayList();
            //循环添加到数组列表
            while (cacheEnum.MoveNext())
            {
                al.Add(cacheEnum.Key);
            }
            //循环从缓存中移除
            foreach (string key in al)
            {
                siteCache.Remove(key);
            }
        }
//RemoveByPattern方法是通过正则移除对应的缓存。
 public static void RemoveByPattern(string pattern)
        {
            IDictionaryEnumerator cacheEnum = siteCache.GetEnumerator();
            Regex regex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
            ArrayList al = new ArrayList();
            //循环从缓存中取出键进行正则条件匹配
            while (cacheEnum.MoveNext())
            {
                //匹配正确则添加到数组列表
                if (regex.IsMatch(cacheEnum.Key.ToString()))
                {
                    al.Add(cacheEnum.Key);
                }
            }
            //移除匹配正则的缓存
            foreach (string key in al)
            {
                siteCache.Remove(key);
            }
        }
//Insert方法是通过Cache的插入方法而实现的,主要能够把缓存键、缓存对象、缓存依赖、缓存过期时间、缓存级别这些缓存项插入到内存中。
    /// <summary>
        /// 插入缓存项
        /// </summary>
        public static void Insert(string key, object value, System.Web.Caching.CacheDependency dep, int seconds, CacheItemPriority priority)
        {
            if (value != null)
            {
                siteCache.Insert(key, value, dep, DateTime.Now.AddSeconds(Factor * seconds), TimeSpan.Zero, priority, null);
            }
        }
//Get方法通过指定的键从Cache中获取缓存
        public static object Get(string key)
        {
            return siteCache[key];
        }
    }

 八、缓存的应用规则

缓存分配的有效期不要太短。
缓存那些经常被访问,同时变化频率不大的数据。
缓存整个应用程序都要使用的设置或对象,并且这些设置和对象在生存期内不会频繁变化。
不要缓存太多项,缓存每个项均有开销。
不要缓存很少使用的项。
不要缓存容易重新计算或随时都可能会修改的对象,如购物车。
不要缓存敏感信息,否则其他人很容易取得这些信息。

比如:可以缓存网站信息配置

GetConfig是一个泛型方法,网站信息配置里的所有功能属性都是通过它来获得对象。方法后面跟着一个where子句,用于指定对类型的约束。其中class限制了类型参数必须是引用类型, new()限制了该类型参数必须具有无参数的公共构造函数。

方法内首先获取了T变量的类型。然后根据类型名拼装成configCacheKey缓存键,通过SiteCache类的Get方法获取缓存的值并存储到configObject变量中。接着判断该缓存是否不存在值,如果不存在,使用GetConfigPath方法获得了T变量的物理文件地址。

public static T GetConfig<T>() where T : class, new()
{
     Type configClassType = typeof(T);
     string configCacheKey = "CK_SiteConfigCode_" + configClassType.Name;
     object configObject = SiteCache.Get(configCacheKey);
     if (configObject == null)
     {
          string configFilePath = GetConfigPath<T>();
//下面检查T变量的物理文件地址是否存在,如果存在即读取T变量的配置信息,并将信息插入到缓存中。其中Insert方法使用了缓存依赖CacheDependency实例监视文件或目录路径,当该资源更改时,缓存的对象将过时,从缓存中移除。
          if (File.Exists(configFilePath))
          {
              using (XmlTextReader xmlTextReader = new XmlTextReader(configFilePath))
              {
                   XmlSerializer xmlSerializer = new XmlSerializer(configClassType);
                   configObject = xmlSerializer.Deserialize(xmlTextReader);
              }
              SiteCache.Insert(configCacheKey, configObject, new CacheDependency(configFilePath)); 
          }
     }
//最后,把缓存对象转换为T泛型变量。判断是否为空,如果是则创建新的T实例返回,否则将原有值返回。
     T config = configObject as T;
     if (config == null)
     {
         return new T();
     }
     else
     {
         return config;
     }
}
 

Asp.Net 基础知识回顾_Cache

标签:层次结构   数据   代理服务   缓存机制   ons   知识   lca   布尔   版本   

原文地址:https://www.cnblogs.com/entclark/p/8654918.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!