15. 应用程序数据的缓存
15.1 前期准备
创建一个利用缓存数据的应用程序:
15.2 数据缓存的使用
DataTable dt = null; Trace.Warn("Page_Load", "looking in cache"); dt = (DataTable)Cache["InventoryDataTable"]; Trace.Warn("Page_Load", "done looking in cache"); if (dt == null) //判D断?是º?否¤?使º1用®?缓o存ä?数ºy据Y { Trace.Warn("Page_Load", "Performing DB lookup"); dt = new DataTable(); string strConnection = @" Data Source=.;AttachDbFilename='D:\Workspace\Visual Studio 2010\培¨¤训¦Ì任¨?务?\2012-01 迭̨¹代䨲2\胡¨²灿¨®业°¦Ì\X\15.应®|用®?程¨¬序¨°数ºy据Y的Ì?缓o存ä?\UseDataCaching\UseDataCaching\App_Data\ASPNETStepByStep4.mdf';Integrated Security=True"; // string strConnection = // @"Data Source= // .\SQLEXPRESS; // AttachDbFilename=|DataDirectory|\ASPNETStepByStep4.mdf; // Integrated Security=True;User Instance=True"; DbProviderFactory f = DbProviderFactories.GetFactory("System.Data.SqlClient"); using (DbConnection connection = f.CreateConnection()) { connection.ConnectionString = strConnection; connection.Open(); DbCommand command = f.CreateCommand(); command.CommandText = "Select * from DotNetReferences"; command.Connection = connection; IDataReader reader = command.ExecuteReader(); dt.Load(reader); reader.Close(); connection.Close(); Cache["InventoryDataTable"] = dt; Trace.Warn("Page_Load", "Done performing DB lookup"); } } return dt;
15.3 缓存的影响
通过GetInventory方法中添加Trace语句,可以跟踪页面看到缓存数据后的效果。
UseDataCaching 应用程序页面的Trace属性默认是被禁用的,但可以启用应用程序级的跟踪。为此设置如下
<configuration> <system.web> <trace enabled="true"/> <compilation debug="true" targetFramework="4.0" /> </system.web> </configuration>
15.4 缓存的管理
Cache提供了一个带参的重载方法Insert
n 设置绝对过期时间
n 设置可调过期时间
n 设置缓存项的依赖项(如数据库、文件和目录依赖项,甚至缓存项之间的依赖项)
n 管理缓存项的相对失效优先级
n 设置缓存项被移除时调用的回调方法
Cache的Insert方法包含4该重载
Insert(String,Object) |
该方法与索引器的设置方法等阶,该方法仅通过一个参数提供的键将Cache中的对象替换 |
Insert(String,Object,CacheDependency) |
该方法用于在Cache中插入对象并将其与一个依赖项关联 |
Insert(String,Object,CacheDependency,DateTime,TimeSpan) |
该方法用于在Cache中插入对象并将其与一个依赖项和过期策略关联 |
Insert(String,Object,CacheDepenDency,DataTime,TimeSpan,CacheItemPriority,CacheItemRemovedCallback) |
该方法用于在Cache中插入对象并将其与一个依赖项和过期策略关联。还可以通过该方法将缓存项与一个回调委托关联,以便在缓存项被移除后通知应用程序 |
15.4.1 内存中的DataSet
/// <summary> /// Summary description for QuotesCollection /// </summary> public class QuotesCollection : DataTable { public QuotesCollection() { // // TODO: Add constructor logic here // } public void Synthesize() { this.TableName = "Quotations"; DataRow dr; Columns.Add(new DataColumn("Quote", typeof(string))); Columns.Add(new DataColumn("OriginatorLastName", typeof(string))); Columns.Add(new DataColumn("OriginatorFirstName", typeof(string))); dr = this.NewRow(); dr[0] = "Imagination is more important than knowledge."; dr[1] = "Einstein"; dr[2] = "Albert"; Rows.Add(dr); …………………..
15.4.2 缓存过期
设置缓存绝对过期:
QuotesCollection quotesCollection; DateTime dtCurrent = DateTime.Now; Trace.Warn("Page_Load", "Testing cache: " + dtCurrent.ToString()); quotesCollection = (QuotesCollection)Cache["QuotesCollection"]; if (quotesCollection == null)//检¨¬查¨¦缓o存ä?中D是º?否¤?存ä?在¨²QuotesColleciton对?象¨®的Ì?实º¦Ì例¤y { quotesCollection = new QuotesCollection(); quotesCollection.Synthesize(); TimeSpan tsExpires = new TimeSpan(0, 0, 15); dtCurrent = DateTime.Now; Trace.Warn("Page_Load", "Caching at: " + dtCurrent.ToString()); Trace.Warn("Page_Load", "This entry will expire in: " + tsExpires.ToString()); Cache.Insert("QuotesCollection", quotesCollection, null, DateTime.MaxValue, tsExpires); }
15.4.3 缓存依赖项
设置缓存依赖项:
15.4.4 SQL Server依赖项
15.4.5 缓存项的清除
ASP.NET支持通过以下3种方式移除缓存项:
n 显示地调用Cache.Remove
n 由于内存占用而移除优先级较低的缓存项
n 移除过期的缓存项
Insert方法的重载方法之一 接受一个回调委托参数。ASP.NET能够通过这个委托来通知缓存项已经被移除。为接收通知,只需要实现一个与其签名一致的(回调)方法,用委托将其包装,并将这个委托传入Insert方法。当缓存项被移除后,ASP.NET会调用这个回调方法。
实现移除回调:
15.5 快速参考
访问数据缓存 |
数据缓存可以通过页面的Cache属性和当前HttpContext的Cache属性访问 |
在缓存中插入数据 |
通过索引符号向缓存插入对象或值 |
在缓存中插入带依赖的数据 |
创建CacheDependency对象,通过Cache.Insert方法重载来一并添加缓存项到这个对象 |
在缓存中插入带过期策略的数据 |
创建DateTime对象,通过Cache.Insert方法重载来添加缓存项到这个对象 |
删除缓存项 |
调用Cache.Remove方法 |
在缓存项被移除后获得通知 |
在缓存添加时传入回调委托 |
16. 输出缓存
16.1 页面内容的缓存
Page 指令的Trace特性
Page指令后面添加OutputCache指令,并至少添加两个特性 Duration 和 VaryByParam。Duration特性用于指定内容被缓存的时长。VaryByParam特性指定是否缓存页面多个版本,这里设none
<%@ Page Language="C#" Trace="false" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="OutputCaching.Default" %> <%@OutputCache Duration="15" VaryByParam="none" %> protected void Page_Load(object sender, EventArgs e) { //Thread.Sleep(10000); Response.Write("This page was generated and cached at: "+ DateTime.Now.ToString()); }
查看浏览器刷新后显示情况
去除Thread.Sleep(10000)注释 查看情况
16.2 缓存内容的管理
16.2.1 OutputCache指令的使用
CacheProfile |
字符串 |
配置文件的名称(在Web.config中定义)。默认值为空字符串 |
Duration |
整数 |
页面或用户控件被缓存的时间(单位秒) |
NoStore |
布尔型 |
用于指导是否发送“no store”缓存控制头(用于禁用敏感信息的二级存储)。对用户控件不适用。默认值为false |
根据查询字符串参数来区分缓存的内容:
16.2.2 HttpCachePolicy
使用HttpCachePolicy能够从另一个角度管理输出缓存。该对象可以通过Response类获得。
Response.Cache.SetNoServerCaching();
Response.Cache.SetLastModified(DateTime.Now);
16.2.3 缓存的位置设置
除了区分页面缓存的版本外,还可以选择缓存的位置。可以通过OutputCache指令的Location属性或HttpCachePolicy类的SetCacheability方法来修改此设置。
OutputCache指令支持一下几种输出缓存的位置设置:
n Any 允许浏览器,下游服务器和服务器缓存页面
n Client值一下在客户端缓存页面
n Downstream 只一下下游服务器和客户端缓存页面
n Server只一下服务器缓存页面
n None禁用缓存
如果使用HttpCachePolicy,则可以编程方式设置缓存内容位置。为此要用到HttpCachePolicy.SetCacheability方法(或HttpResponse.CacheControl属性),它接受一个HttpCacheability枚举参数。这个枚举包含以下成员,它们要逼OututCache指令中的Location 属性值更容易理解:
n NoCache禁用缓存
n Private只允许在客户端上缓存
n Public允许在客户端和共享代理上缓存
n Server允许在服务器上缓存
n ServerAndNoCache只允许在服务器上缓存输出,禁止在其他位置上进行缓存
n ServerAndPrivate只允许在服务器和客户端上缓存输出,禁止在其他位置上进行缓存(不允许代理服务器缓存输出)
16.2.4 输出缓存依赖项
16.2.5 缓存配置文件
设置配置文件:
Web.config文件
<configuration> <system.web> <compilation debug="true" targetFramework="4.0" /> <caching> <outputCacheSettings> <outputCacheProfiles> <add name="profiles" duration="60" varyByParam="TextBoxName"/> </outputCacheProfiles> </outputCacheSettings> </caching> </system.web>
修改页面中的OutputCache指令
<%@ Page Language="C#" Trace="false" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="OutputCaching.Default" %> <%@OutputCache CacheProfile="profile" %>
16.3 用户控件的缓存
缓存用户控件的输出:
添加用户控件 SiteMenu
头部添加 <%@ OutputCache Duration="60" VaryByParam="none" %>
在新页面 UseSiteMenuControl.aspx上 添加SiteMenu控件
启用页面跟踪 Trace="true"
浏览
刷新 发现 ASP.NET使用缓存的控件来替代了整个SiteMenu控件
16.4 适合应用输出缓存的场景
页面中的控件生成大量HTML
16.5 其他缓存提供程序
ASP.NET引入了一种新的输出缓存功能,允许将输出存储在内存以外的位置。开发者可以指定其他能够管理页面输出缓存的提供程序。这有助于实现高伸缩性策略(如云计算)。
自定义的输出缓存提供程序应派生自OutputCacheProvider类,并至少重写Add,Get,Remove和Set方法。Add方法用于添加缓存项,Get方法用于获取指定的缓存项,Remove用于删除缓存项,Set方法用于替换现有缓存项。
16.6 快速参考
缓存页面的输出 |
为页面添加OutputCache指令 |
根据查询字符串参数的不同来缓存不同版本的页面 |
设置OutputCache指令的VaryByParam特性 |
根据标头的不同来缓存不同版本的页面 |
设置OuputCache指令的VaryByHeader特性 |
根据浏览器不同了缓存不同版本的页面 |
将OuputCache指令的VaryByCustom特性设置为browser |
指定缓存内容位置 |
可以通过OuputCache指令的Location特性指定 |
以编程方式访问缓存属性 |
使用Response对象的Cache属性,该对象时HttpCachePolicy类的实例 |
通过web.config来管理输出缓存的行为 |
在web.config文件中添加outputCacheProfile元素,并在需要时引用 |
缓存用户控件 |
在用户控件的.ascx文件中添加OuputCache指令 |
诊断与插件
17. 诊断与调试
17.1 页面跟踪
Page类的Trace属性
17.1.1 跟踪
启动页面跟踪非常简单。只需要将页面中的Page指令的Trace特性设置为true即可。
17.1.2 跟踪语句
添加跟踪语句:
protected void Page_Load(object sender, EventArgs e) { alTableEntries = (ArrayList)this.Session["TableEntries"]; if (alTableEntries == null) { Trace.Warn("Page_Load", "alTableEntries is null");//Trace.Warn输出文本会以红色呈现 alTableEntries = new ArrayList(); } AssembleTable(); } protected void AssembleTable() { this.Table1.Rows.Clear(); foreach (String s in alTableEntries) { Trace.Write("AssembleTable", "String found: " + s); //语句跟踪语句 TableRow row = new TableRow(); TableCell cell = new TableCell(); cell.Text = s; row.Cells.Add(cell); this.Table1.Rows.Add(row); } } protected void Button1_Click(object sender, EventArgs e) { Trace.Write("Button1_Click", "Adding string: " + this.TextBox1.Text);//语句跟踪语句 alTableEntries.Add(this.TextBox1.Text); this.Session["TableEntries"] = alTableEntries; AssembleTable(); }
17.2 应用程序跟踪
启用应用程序跟踪,需要设置web.config:
<configuration>
<system.web>
<trace enabled=”true”/>
</system.web>
</configuration>
使用应用程序级的跟踪:
1. 删除Page指令的Trace 特性
在web.config中启用应用程序级跟踪<trace enabled="true"></trace>
2. Ctrl+F5组合键,运行页面。
3. 在地址栏TraceMe.aspx修改为Trace.axd。这个URL会请求一个特殊处理程序,它能够呈现存储在内存中的跟踪结果。
17.2.1 以编程方式启用跟踪
protected void Page_Load(object sender, EventArgs e) { } protected void Button1_Click(object sender, EventArgs e) { if (this.TextBoxSecretCode.Text == "password") { this.Trace.IsEnabled = true;//启?用®?跟¨²踪Á¨´ } } protected void Button2_Click(object sender, EventArgs e) { this.Trace.IsEnabled = false;//禁?用®?跟¨²踪Á¨´ }
17.3 使用Visual Studio 进行调试
调试应用程序:
Web.config
<compilation debug="true" targetFramework="4.0"/> </system.web> </configuration>
17.4 错误页面
我们可以通过修改web.config使ASP.NET在应用程序发生错误时发挥指定的页面。表17.2列出了web.config中设置自定义错误页面的相关设置。
defaultRedirect |
发生异常时显示的错误页面 |
Mode |
On=显示自定义的页面 |
remoteOnly |
向客户端显示自定义的错误页面,而只在本地显示ASP.NET的错误页面 |
设置错误页面:
Web.config
<configuration> <system.web> <trace enabled="true"/> <compilation debug="true" targetFramework="4.0"/> <customErrors defaultRedirect="SomethingBadHappened.htm" mode="On"> <error statusCode ="404" redirect="404Err.htm"/> </customErrors> </system.web> </configuration>
17.5 处理未处理的异常
新建全局应用处理程序
Global.asax
<%@ Application Language="C#" %> <script runat="server"> protected void Application_Start(object sender, EventArgs e) { } protected void Session_Start(object sender, EventArgs e) { } protected void Application_BeginRequest(object sender, EventArgs e) { } protected void Application_AuthenticateRequest(object sender, EventArgs e) { } protected void Application_Error(object sender, EventArgs e) { Exception ex = Server.GetLastError(); System.Diagnostics.Debug.WriteLine("Error in app: " + ex); System.Diagnostics.Debug.WriteLine("Error in app: " + ex); if (ex is HttpUnhandledException) { Context.ClearError(); Server.Transfer("somethingbadhappened.htm"); } else { } } protected void Session_End(object sender, EventArgs e) { } protected void Application_End(object sender, EventArgs e) { } </script>