Web开发之ASP.Net:(5)WebForm(.aspx) (二)

作者:陆金龙    发表时间:2016-08-21 15:00   


 

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>

 

2Session值的共享

配置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 />");

    }

}

 

附:请求处理生命周期图