Web开发之ASP.Net:(5)WebForm(.aspx) (二)
3.1 Cookie:浏览器端实现状态保持
HTTP协议下的方式,就是在客户端保存客户端单独使用的数据,数据一定是可有可无的。
3.1.1 Cookie介绍
Cookie是一种能够让网站服务器把少量数据(4kb左右)储存到客户端的硬盘或内存,并且读取出来的一种技术。
当你浏览某网站时,由Web服务器放置于你硬盘上的一个非常小的文本文件,它可以记录你的用户ID、浏览过的网页或者停留的时间等网站想要你保存的信息。当你再次通过浏览器访问该网站时,浏览器会自动将属于该网站的Cookie发送到服务器去,服务器通过读取Cookie,得知你的相关信息,就可以做出相应的动作。
开发场景:感兴趣的广告,最近浏览的商品,不用输入ID、密码就自动登录等等。(如果换了一天电脑,还有用户最近数据,是记录在服务器是数据库里面,关联用户)
网站相关(不同网站不共享Cookie文件数据)
浏览器相关(不同浏览器不共享Cookie文件数据)
3.1.2 Cookie的使用
浏览器保存Cookie有两种方式:
(1)、浏览器的内存中
没有设置过期时间只保存在内存中,其实就是浏览器的进程内,下次用浏览器就没数据了;
(2)、浏览器所在的电脑的硬盘中。
为将要写入的浏览器的Cookie对象设置失效时间,下次浏览器开启就能读取Cookie:Cook Expires = DateTime.Now.AddMinutes(5);
上次登录的用户名,最近访问的商品.
从浏览器发来的cookie的Expires属性值是无效的。(浏览器在向服务器发送Cookie的时候,没有将Cookie的失效时间发送过去)
服务器设置Cookie:
HttpCookie cok = new HttpCookie(“uId”, “10001”);//(“键”,”值”)
cok.Expires = DateTime.Now.AddDays(18);//设置失效日期-现在之后的18天后
context.Response.Cookies.Add(cok); //添加到响应中
服务器获得客户端传来的Cookie:
string strUName=context.Request.Cookies[“uId”].Value;//从请求中获得Cookie
(3)、cookie.Path(为指定的文件夹生成Cookie)
hc.Path="/../admin";只有admin文件夹下的页面才可读取hc这个Cookie。
cookie.Domain (域/域名) www.baidu.com img.baidu.com video.baidu.com
(4)、Cookie特点
Cookie是和站点相关的,并且每次向服务器请求的时候除了发送表单参数外,还会将和站点相关的所有Cookie都提交给服务器,是强制性的。Cookie也是保存在浏览器端的,而且浏览器会在每次请求的时候都会把和这个站点的相关的Cookie提交到服务器,并且将服务端返回的Cookie更新到硬盘,因此可以将信息保存在Cookie中,然后在服务器端读取、修改。
服务器返回数据除了普通的html数据以外,还会返回修改的Cookie,浏览器把拿到的Cookie值更新本地浏览器的Cookie就可以。
哪怕请求jpg、js、css这种文件也会带着Cookie,因为服务器端可能要进行Session的操作(SeesionId保存在Cookie中的),比如判断是否已登录。
互联网优化的案例:因为每次请求jpg,都会带上Cookie,占用比较多的流量,可以设置图片服务器和主站域名不一样,这样再请求图片时,就不会携带主站产生的那些Cookie了,降低了传输中Cookie的流量。(面试时聊网站调优)
优酷这样的视频 设置专用的视频服务器 与主站(主站上只放视频的链接)分离
Cookie的缺点:和表单一样,而且还不能存储过多信息。客户端、服务器端设置的Cookie双方都能读。比如:除了服务器可以操作Cookie外,浏览器可以通过js来操作Cooikie。
3.1.3 Cookie应用(记住我:自动登录)
真实场景中:
Cookie一定要对密码加密,或者不存密码,只存用户名。
//读Cookie 写Cookie 设置Cookie过期
public partial class ULogin : System.Web.UI.UserControl
{
/// <summary>
/// 读Cookie,如果有数据,且验证通过则自动登录(直接转到ShowMsg.aspx)
/// </summary>
protected void Page_Load(object sender, EventArgs e)
{
//Cookies["uu"]为空,赋值可能会报错,所以判断Cookies["uu"]本身是否为空,而不是判断他的值
//如果读到cookie,获取用户信息
if (!string.IsNullOrEmpty(Context.Request.Cookies["uu"])&&!string.IsNullOrEmpty(Context.Request.Cookies["pp"]))
{
string loginId = Context.Request.Cookies["uu"].Value;
string pwd = Context.Request.Cookies["pp"].Value;
UsersBLL bll = new UsersBLL();
Users user = bll.GetModel(loginId);
if (user!=null)
{
//验证cookie密码通过,跳转
if (pwd==user.LoginPwd)
{
Session["user"] = user;
Response.Redirect("../ShowMsg.aspx?msg=登录成功!" "&url=/Default.aspx" "&txt=返回首页");
}
//cookie失效,移除Cookie,用response设置过期
else
{
Response.Cookies["uu"].Expires = DateTime.Now.AddDays(-1);
Response.Cookies["pp"].Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(ck1);
Response.Cookies.Add(ck2);
}
}
//如果没有获得用户信息,已修改,进入登录页面
}
//如果没有读取到cookie,不作处理,进入登录页面
}
/// <summary>
/// 正常登录 写CooKie
/// </summary>
protected void btnLogin_Click(object sender, ImageClickEventArgs e)
{
string loginId = txtLoginId.Text;
string pwd = txtLoginPwd.Text;
string msg = string.Empty;
Users model = new Users();
UsersBLL bll = new UsersBLL();
if (bll.CheckUser(loginId, pwd, out msg, out model))
{
//登录成功 ShowMsg.aspx
//如果用户选择记住了我
Session["user"] = model;
if (cbAutoLogin.Checked==true)
{
//创建Cookie,在内存中
HttpCookie ck1 = new HttpCookie("uu",model.LoginId);
HttpCookie ck2 = new HttpCookie("pp",Common.Common.Encrypt(model.LoginId));
ck1.Expires = DateTime.Now.AddDays(3);
ck2.Expires = DateTime.Now.AddDays(3);
//写入到磁盘文件中 不要丢了!!!
Response.Cookies.Add(ck1);
Response.Cookies.Add(ck2);
//或者
// Response.AppendCookie(new HttpCookie("uu",model.LoginId))
}
//跳到登录前的页面
if (!string.IsNullOrEmpty(Request.QueryString["url"]))
{
Response.Redirect(Request.QueryString["url"]);
}
Response.Redirect("../ShowMsg.aspx?msg=" msg "&url=/Default.aspx" "&txt=返回首页");
}
else
{
//登录失败,跳到图书列表页面
Response.Redirect("../ShowMsg.aspx?msg=" msg "&url=/booklist.aspx" "&txt=返回到图书列表页面");
}
}
}
3.1.4 Cookie的域名和路径
域名设置:
主域的Cookie是能被所有的子域访问到的,而主域要访问到子域的Cookie,则需要子域将自己的Cookie的域设置为主域。
如:在 www.tieba.baidu.com对cookie可做如下设置
HttpCookie ck1 = new HttpCookie("uu","admin");
ck1.Domain= "www.baidu.com";
如果想让子域Cookie让主域能访问,同时还要做如下设置
ck1.secure=false;
路径设置:
ck1.Path= "/WebSiteCookie/cookie";
只允许WebSiteCookie/cookie文件夹下的页面访问这个ck1/cookie
3.2 ViewState:aspx单页面级状态保持
3.2.1 ViewState原理
ViewState依赖于隐藏域,由服务端Response.Write时写到页面的隐藏域中。
使用ViewState,页面上必须有一个服务器端窗体标记(<form runat=“server”>) 。
ASP.NET 的.aspx页面特有,页面级的,跟页面生命周期相关。页面一关闭,ViewState中的值就访问不到了。
服务器在接收到用户请求一个页面后,会自动在请求报文中找看是否包含__VIEWSTATE的隐藏域,如果有,则将中间的值解码后添加到页面的ViewState属性中,以备用。
服务器在输出的时候,也会自动的将新的ViewState值添加到表单里名叫__VIEWSTATE的隐藏域中。
ViewState是在页面上的一个隐藏域中保存客户端单独使用的数据的方式,适用于同一个页面在不关闭的情况下多次与服务器交互。
典型应用:
1. IsPostBack依赖于ViewState,通过是否获取到ViewState内容判断。
注意:一定要是运行在Asp.Net服务端(runat=”server”)的表单提交,才能获取到IsPostBack。自己写的静态页面类型的表单提交,不能获取到IsPostBack。
2. 服务端监听change事件,通过ViewState内容与表单内容比较。
3. 表格上的点击事件可以用Viewstate
内网系统、后台管理页面可以尽情的用ViewState。
互联网前台页面一般都要禁用掉ViewState,因为ViewState消耗很多带宽。
3.2.2 ViewState保存的数据
1)用户自定义的数据保存方式
数据保存方式 ViewState["myKey"]="MyData";
读取数据方式: string myData;
if(ViewState["myKey"]!=null)
{ myData=(string)ViewState["myKey"]; }
2)非表单元素的状态自动保存在ViewState中
3)表单元素中的非单值服务器控件的状态也自动保存在ViewState中
单值表单元素的值,通过post提交,不受ViewState是否禁用的影响
非单值元素的值,能通过ViewState提交到服务端。
4)为什么要序列化? --ViewState中存放字符串
注意:ViewState不能存储所有的数据类型,仅支持可序列化对象。
要把对像发送到另一台电脑(客户端和服务端之间传递),就需要处理
把对象进行序列化--字节数组--字符串,然后才进行Base64编码
3.2.3 ViewState的禁用
EnableViewState="false"后ViewState将失效,考虑其占用流量,需要时可这样设置禁用。
禁用单个控件的ViewState设定EnableViewState="false";
禁用整个页面(所有控件的ViewState,IsPostBack不受影响),在aspx的Page指令区加EnableViewState="false" 。
WebForm的IsPostBack依赖于__ViewState,整个页面的ViewState禁用会影响IsPostBack。
3.2.4 ViewState应用
(1)基本应用 ViewState的存值和取值
public partial class _01_viewstate : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Person p = new Person();//在person定义的时必须标记[Serializable]
p.Name = "张三";
ViewState["p"] = p;
if (!IsPostBack)
{
//首次加载
ViewState["num"] = 0;
}
else
{
//postback
int n = Convert.ToInt32(ViewState["num"]);
n ;
ViewState["num"] = n;
}
Response.Write(ViewState["num"].ToString());
}
}
(2)非表单元素及EnableViewState="false"、单值表单元素(不用ViewState保存)
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" runat="server" Text=""></asp:Label>
<asp:Label EnableViewState="false" ID="Label2" runat="server" Text=""></asp:Label>
<asp:TextBox EnableViewState="false" ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Button" />
</div>
</form>
</body>
</html>
注意控件的IsPostBack属性
4. 服务端状态保持Cache、Session、Application
ASP.NET系统对象小结:
系统对象 ASP.NET
Request对象 读取客户端在Web请求期间发送的值
Response 对象 封装了页面执行期返回到HTTP客户端的输出
Server 对象 提供对服务器上的方法和属性的访问
Cookie 对象 客户端保持会话信息的一种方式(相对类说对安全要求不高的时候使用)
Session 对象 会话期状态保持对象,用于跟踪单一用户的会话 (安全)
Application对象 作用于整个程序运行期的状态对象(保存网站共享数据)
(还有个Page对象,即页面类本身)
Cookie和Session都是为每一个客户端设置的对象,一个保存在客户端 一个保存在服务端。
Appillacation 是为所有客户端提供的。注意Lock();谁都可以修改的。
aspx执行流程(比ashx更多的部分)
Load (我们自己写的)
Page 在 Page 上调用 OnLoad 事件方法,然后以递归方式对每个子控件执行相同操作,如此循环往复,直到加载完本页和所有控件为止。
使用 OnLoad 事件方法来设置控件中的属性并建立数据库连接。
Render (输出给控件浏览器)
这不是事件;在处理的这个阶段,Page 对象会在每个控件上调用此方法。所有 ASP.NET Web 服务器控件都有一个用于写出发送给浏览器的控件标记的 Render 方法。
如果创建自定义控件,通常要重写此方法以输出控件的标记。不过,如果自定义控件只合并标准的 ASP.NET Web 服务器控件,不合并自定义标记,则不需要重写 Render 方法。
用户控件(.ascx 文件)自动合并呈现,因此不需要在代码中显式呈现该控件。
4.1 Session:页面间传值对象
4.1.1 Session相关
SessionId保存在浏览器客户端,Session的值存在服务端。
(1)简介
* 因为在服务器端保存 可以存储任意类型对象。
* 每个客户端的Session是独立存储。
* 在整个用户会话过程中保留此信息,会话过期(默认超过20分钟)或终止(如:关闭浏览器),服务器会清除Session对像(SessionId以Cookie的方式保存在客户端的内存中,没有设置过期的,浏览器关闭后,SessionId就没有了)
*常用于保存登录用户ID,判断是否登录过,控制其访问页面的权限。
(2)属性 描述
SessionID 唯一用户会话标识符
TimeOut 用户超时(单位:分钟),默认20分钟
Count 会话状态集合中的项目数
(3)执行过程
* Response.Write(System.Reflection.Assembly.GetExecutingAssembly().Location);//编译后的dll路径
* 服务器会在响应报文中以Cookie的方式将SessionId返回给浏览器,注意没有设置过期时间,只在浏览器内存中
Set-Cookie:ASP.NET_SessionId=1fjkiqjflhqfw1sfzgzzod4o; path=/; HttpOnly
* 重新请求(转向)的时候带上了SessionId Cookie: ASP.NET_SessionId=1fjkiqjflhqfw1sfzgzzod4o
(4)一般处理程序中使用Session,需做如下设置
(A)导入命名空间using System.Web.SessionState;
(B)处理请求的类,要实现一个接口IRequiresSessionState
4.1.2 Session使用
(1)写Session:
if (name == "admin" && pwd == "admin")
{
//登录成功 记录用户登陆的状态
//Context.Session.Abandon();//销毁Session
Session["user"] = name;
Response.Redirect("07-SessionLoginOver.aspx");
}
(2)读Session:只要注意一点,读取之后,使用之前,判断不为空
public partial class _07_SessionLoginOver : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//判断用户是否是登陆状态
if (Session["user"] != null)
{
Response.Write("欢迎" Session["user"].ToString() "登陆");
}
else
{
Response.Write("<script>alert('请先登陆');location.href='07-SessionLogin.aspx'</script>");
}
}
}
(3)销毁、清空Session
Session.Abandon();//销毁服务器端的Session对象
Session.Clear();//清空服务端的Session对象里的键值对,Session对象并没有从Session池里销毁
4.1.3进程内Session(默认)
(1)进程内Session mode="Inproc" 该参数使Session的保存依赖 ASP.NET进程,由于某些事件导致进程重启时,Session会丢失。
ASP.Net已经内置了Session机制。不要放太多的对象到Session(因为存储在服务器端的一个辅助进程位w3wk(工作者进程)里,不稳定,数据多了容易丢失),Session会有超时销毁的机制。
20分钟的默认值,是从最后一次请求开始计时(滑动计时方式),淘宝买东西,会挑很久,避免出现点击购买提示请先登录,所以从刚登录开始计时,不合适。每次请求(访问一个商品),重新计时。
(2)如果浏览器禁用了Cookie,会导致没法登录,可以启用Url来传递SessionID。做如下设置(临时处理):
但是一般不考虑Cookie的禁用
<system.web>
<sessionState cookieless="true" timeout="30"> </sessionState>
(3)可以看到Session机制并不是Http协议规定的,是ASP.net实现的,现在PHP、JSP等大部分服务端技术都实现了Session,原理都差不多。
4.1.4进程外Session(解决Session丢失)
StateServer和SQLServer 模式 对象必须可序列化。
1)mode="StateServer"
StateServer是本机的一个服务,除非电脑重启,或State Service崩溃,Session才会丢失。
(A)开启 ASP.NET 状态服务
(B)配置 <sessionState mode="StateServer" stateConnectionString="tcpip=localhost:42424"></sessionState>
若StateServer在本机存储,localhost可以为127.0.0.1;若StateServer为远程服务器,则改为远程服务器IP地址
(C)如果是远程的stateserver,修改注册表(regedit.exe) 配置注册表,修改状态服务器 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters\AllowRemoteConnection 置为1
2)mode="SQLServer"
将Session保存在数据库中,使用SQLServer。在机器重启后Session也不会丢失。
(A)必须开启SQLServer代理服务,此服务负责清除过期的Session,若没有开服务,则Session不会过期。
(B)web.config设置 <sessionState mode="SQLServer" sqlConnectionString="Data Source=.;Initial Catalog=test;uid=sa;pwd=woshinibaba" allowCustomSqlDatabase="true" ></sessionState>
(C)数据库配置 aspnet_regsql.exe -S 127.0.0.1 -U sa -P 123 -ssadd -sstype c -d test
注意:ASP.NET 2.0版本后微软提供了aspnet_regsql.exe工具可以方便的配置Session数据库。该工具位于 Web 服务器上的"系统根目录\Microsoft.NET\Framework\版本号"文件夹中.
可以再-U –P 与 -E中选择一组. –E表示以当前系统用户通过windows身份验证登录数据库, -U -P则是使用SqlServer用户登录数据库. -ssadd表示是添加Session数据库, -ssremove表示移除Session数据库.-d 是数据库名。
4.1.5 Session共享的解决方案
(1)客户端SessionID值唯一(重置SessionID)
对于不同的域名:主域名、子域名、跨站点域名或跨服务器域名,用户在打开页面时会产生不同的SessionID,为了使这些站点在用户登录时只登录一次,那我们就要解决SessionID的问题,必须使SessionID在这些共享Session的站点中只产生一次。而SessionID是存储在客户端的cookie之中键值为ASP.NET_SessionId的一个字符串(也可以存储在URL中,这里不作介绍),为此只须使各站点存储的SP.NET_SessionId唯一即可。
因每个客户端在打开时会产生一个SessionID,为此我们要做的就是重置SessionID。我们可以在继承HttpModule,在结束请求时重写SessionID。
为使用以上代码,须配置下面节点项。
<httpModules>
<add name="节点名称" type="类名全称, 程序集"/>
</httpModules>
(2)Session值的共享
配置sessionState节点,使用StateServer或SQLServer来实现Session共享。
为实现跨服务器共享,必须在Web.config配置:
<machineKey decryptionKey="FD69B2EB9A11E3063518F1932E314E4AA1577BF0B824F369" validationKey="5F32295C31223A362286DD5777916FCD0FD2A8EF882783FD3E29AB1FCDFE931F8FA45A8E468B7A40269E50A748778CBB8DB2262D44A86BBCEA96DCA46CBC05C3" validation="SHA1" decryption="Auto"/>
并且,不同服务器上站点配置必须用相同的Web.config,各站点目录配置也要相同。
4.1.6 Session过期跳转处理
session每次过期都要经过global文件中的Application_Error方法,在其中验证,判断返回登陆页面就可以了
protected void Application_Error(Object sender, EventArgs e)
{
string URL = HttpContext.Current.Request.Url.ToString ();
if(Server.GetLastError() is HttpUnhandledException)
{
Server.ClearError();
this.Server.Transfer("Login.aspx?ref=viewstate",true);
}
else
{
Server.ClearError();
this.Server.Transfer(URL,true);
}
}
如果某些页面不想用户频繁登陆,可以用一个定时器发送请求到服务端。
4.2 Application:整个运行期共享对象
4.2.1 Application简介
作用于整个程序运行期的状态对象(保存网站共享数据)
protected void Page_Load(object sender, EventArgs e)
{
Application.Lock();
Application["num"] = 1;
Application.UnLock();
}
添加Web→全局应用程序类,注意文件名不要改。
全局文件是对Web应用生命周期的一个事件响应的地方
将Web应用启动时初始化的一些代码写到Application_Start中。应用关闭的时候Application_End调用。
当一个Session启动的时候Session_Start被调用,Session结束(用户主动退出或者超时结束)Session_End被调用。
当一个用户请求来的时候Application_BeginRequest方法被调用
当应用中出现未捕获异常,Application_Error被调用(常考,ASP.Net中的错误处理机制),用HttpContext.Current.Server.GetLastError()获得异常信息,然后用Log4Net记录到日志中。
4.2.2 Application应用:记录在线人数
Global.asax -- 记录当前网站同时在线人数,Session会导致该数据不准确,浏览器关闭走了之后要等Session过期之后才触发Session_End。
<%@ Application Language="C#" %>
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
//在应用程序启动时运行的代码
Application.Lock();
Application["num"] = 0;
Application.UnLock();
}
void Application_End(object sender, EventArgs e)
{
//在应用程序关闭时运行的代码
}
void Application_Error(object sender, EventArgs e)
{
//在出现未处理的错误时运行的代码
}
void Session_Start(object sender, EventArgs e)
{
//在新会话启动时运行的代码
Application.Lock();
Application["num"] = Convert.ToInt32(Application["num"]) 1;
Application.UnLock();
}
void Session_End(object sender, EventArgs e)
{
//在会话结束时运行的代码。
// 注意: 只有在 Web.config 文件中的 sessionstate 模式设置为
// InProc 时,才会引发 Session_End 事件。如果会话模式
//设置为 StateServer 或 SQLServer,则不会引发该事件。
Application.Lock();
Application["num"] = Convert.ToInt32(Application["num"]) - 1;
Application.UnLock();
}
</script>
4.3 Cache:服务端缓存
如果网站性能不好,优化时,第一考虑的就是缓存。
读缓存的效果展示:获取Photos表的数据
在获取数据的后加以下代码检测,显示读数据库约2078ms 读缓存只要15-31ms,差别近100倍,确实巨大!
TimeSpan ts = DateTime.Now - Context.Timestamp;//Context.Timestamp或取当前Http请求的时间戳
Response.Write(ts.TotalMilliseconds);
缓存(Cache)是一种用空间换取时间的技术,存在于计算机中很多地方,用来将一些慢速设备中的常用数据保存在快速设备中,取数据的时候直接从快速设备中取。比如CPU二级缓存、内存、windows文件读取缓存。
为了保证从缓存中读取数据和慢速数据(数据库)中数据一致,则需要在慢速数据(数据库)中对应的数据发生变化的时候,清除缓存中相应的数据。
缓存是改进网站性能的第一个手段,就像索引是改进数据库性能的第一个手段一样。 ASP.net缓存主要分为:页面缓存(中庸)、数据源缓存(最不灵活的)、数据缓存(灵活)这三种主要类型。
4.3.1 页面缓存
Cache是放在服务端内存的,由服务端从内存取数据响应给客户端。
给页面添加<%@ OutputCache Duration=“15” VaryByParam=“none”%>标签就可以启用页面缓存。
Duration:缓存过期时间,单位:秒
请求间隔时间超过这个时间后,重新返回新的数据。
VaryByParam:引起缓存失效的参数
VaryByParam=“none” 任何参数的变化都不会触发缓存失效。
VaryByParam=“*”,是请求发生任何变化,都会触发缓存失效,会返回新的数据。
这样整个页面的内容都会被缓存,页面中的ASP.Net代码、数据源在缓存期间都不会被运行,而是直接输出缓存的页面内容。 Duration表示缓存时间,以秒为单位,超过这个时间则缓存失效,再次生成以后会再缓存15秒,以此类推。在Page_Load处设置断点、修改数据库数据测试。这个缓存是在服务器缓存的,不是在客户端,因为用HttpWatch还是能看到向服务器提交的请求的,只不过服务器看到有缓存就没有再执行页面类。一般只有看帖、看新闻、看视频的页面才缓存,CUD的页面没必要缓存
对于看新闻页面来讲,如果如上设置的话,则会缓存在第一个看到的新闻,因为?id=2、?id=3只是页面的不同参数而已,为了能让不同的新闻各自缓存,因此可以设置<%@ OutputCache Duration=“15” VaryByParam=“id”%>,表示对于相同页面的不同的id参数进行单独缓存。如果有多个确定缓存的参数,则将参数名用分号隔开即可,比如VaryByParam=“id;number”。测试。缓存可能会有过期数据的问题,因此根据需求选用。
如果想让任何不同的查询字符串都创建不同的缓存,则设置VaryByParam="*",一般情况下设置“*”就足够。
4.3.2 数据源缓存
为ObjectDataSource控件设置缓存。
设定ObjectDataSource的CacheDuration=10(缓存时间:秒),一般设置10-20秒。EnableCaching=true。这样每隔CacheDuration指定的时间段才调用SelectMethod指定的方法来执行数据库查询,其他时候都是直接返回缓存的数据。
取数据的过程,在缓存期间,绑定控件向ObjectDataSource要数据, ObjectDataSource直接将缓存的数据返回给控件,不再去向TypeName指向的类要数据。
适用于数据变化不频繁的情况。
4.3.3 自定义缓存
非常重要!文件依赖和数据库依赖两种依赖方式。
使用场景:访问量大,变化比较少。如京东的菜单项。
1) 缓存的存储和读取
页面加载时,绑定数据优先从缓存取,没有缓存再查数据库。
if (Cache["Photos"]==null)
{
PhotosBLL bll = new PhotosBLL();
Repeater_photos.DataSource = bll.GetPhotos();
Cache["Photos"] = bll.GetPhotos();
}
else
{
Repeater_photos.DataSource = Cache["Photos"];
Response.Write("读取了缓存<br/>");
}
2)缓存的文件依赖
上述的缓存,除了第一次读数据库,以后每次都读到缓存,除非服务器重启,或服务器内部机制清理了缓存。
要考虑数据发生改变的时候,Cache自动被清理的机制。--缓存依赖
文件缓存依赖,是为缓存绑定一个文件,当文件或路径发生变化时,缓存失效。
对上述代码稍作修改:
string path = @"D:\...\0920 控件-MyPhotos\DataBind\CacheTest\TestFile.txt";
CacheDependency cd = new CacheDependency(path);
Cache.Insert("Photos", bll.GetPhotos(), cd);
如果数据是从文件来的话,使用文件依赖比较合适。
3)缓存的数据库依赖:(轮询机制)
了解,用得不多。
根据poolTime设置的时间间隔(ms 毫秒),轮询数据库,检查是否变化。如果变化,缓存失效。
3.1) 数据库启用缓存依赖 以命令行方式执行SqlCacheDependency的配置。
在vs2010的命令提示符中运行(切换到aspnet_regsql.exe所在的目录)
aspnet_regsql -S localhost -U sa -P 123@abc -ed -d myphotos -et -t photos (给photos这个表启动缓存依赖)
//说明:
(A)在Myphotos数据库实例下生成了一张表AspNet_SqlCacheTablesForChangeNotification包含字段tableName, notificationCreated, changeId
(B)报错处理:“C:\Program Files\Microsoft Visual Studio 10.0\VC下的aspnet_regsql.exe不是有效的Win32应用程序”
C:\Program Files\Microsoft Visual Studio 10.0\VC 下的aspnet_regsql.exe文件已损坏,将C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319下的aspnet_regsql.exe文件复制过来覆盖掉即可。
3.2) 依赖于数据库的web.config配置
<system.web>
<caching>
<sqlCacheDependency>
<databases>
<add name="myphotos" connectionStringName="connstr" pollTime="500"/>
</databases>
</sqlCacheDependency>
</caching>
//connectionStringName写connectionString节点下那个使用到的连接的name的值
3.3) 数据库依赖对像创建
SqlCacheDependency scd = new SqlCacheDependency("myphotos", "photos");
Cache.Insert("Photos", bll.GetPhotos(), scd);
//注意:
(A)"myphotos"完全同web.config中配置的<databases>节点中的name,"photos"完全同命令行启用缓存时设置的表名,大小写都不能错!!!
(B)设置过期时间
Cache.Insert("Photos",
bll.GetPhotos(), scd,DateTime.Now.AddMinutes(10),Cache.NoSlidingExpiration);//这里采用绝对过期时间模式,要同时声明不使用滑动过期时间模式。
静态页面的缓存,可以通过设置头部实现。
5. Asp.Net aspx页面生命周期
注:所有的aspx页面都继承自一个类:Page 类(System.Web.UI.Page)。
在第8个事件:
创建一般处理程序的对象或页面对象的实例。
在第11与12 个事件之间:
如果是一般处理程序,直接执行创建的实例的ProcessRequest方法。
如果是aspx页面,则调用Page的ProcessRequest方法执行页面生命周期。
public partial class PageLife_Default : System.Web.UI.Page
{
//预初始化
protected void Page_PreInit(object sender, EventArgs e)
{
Response.Write("开始Page_PreInit.....<br />");
}
//开始初始化
protected void Page_Init(Object sender, EventArgs e)
{
Response.Write("开始Init..... <br />");
}
//页面加载所有控件,控件已经有数据到控件上了,可以直接this.txtBox.Text获取到数据
protected void Page_Load(object sender, EventArgs e)
{
Response.Write("开始load.....<br />");
}
//事件响应方法执行
protected void Button1_Click(object sender, EventArgs e)
{
Response.Write("开始执行页面事件响应方法.....<br />");
}
}
附:请求处理生命周期图