学习笔记 --- ASP.NET状态管理
这篇是以前写的, 觉得配置文件(个性化数据那块) 和 缓存那里不够详细, 一直没发. 既然决定要专门整理一篇缓存笔记. 现在, 就直接发布下吧
##############################################
先别管ASP.NET的状态管理是什么? 首先回想一下浏览器和服务器的请求通信过程: 浏览器和服务器之间采用了HTTP协议作为共有约定来进行通信. 当在浏览器的地址栏中输入一个网址(IP地址)并按回车时(不考虑网络设备向DNS请求IP地址的过程), 浏览器首先发送一个GET请求到服务器, 服务器接收请求后根据模板页(default.aspx)和后台CS文件(default.aspx.cs)生成页面并回送给浏览器, 于是浏览器接收回送的消息并经浏览器编译解释后呈现给用户, 这时用户就可以看到页面上的各种元素了. 当用户希望执行某项操作时, 如: 点击button按钮, 这时浏览器将再次向服务器发送请求(Post请求)并附加上请求参数, 其中请求参数包含各种页面元数据的信息及状态参数; 当服务器接收到请求后, 将再次根据模板页和后台cs文件生成页面, 随后将请求参数中状态参数赋给相应的控件, 在页面事件的Load事件 --- LoadComplete事件之间, 执行控件事件, 即执行button的click事件的处理方法. 当页面事件处理完后, 将生成的页面再次返回到客户端浏览器. 这样, 看起来像是点击了button按钮, 执行了button的click事件绑定的方法.
而实际上, 服务器在接受到GET请求并回送给客户端浏览器后, 将直接销毁掉刚才创建的页面对象, 也就是说服务器生成页面的过程都是”一次性”服务, 再把生成好的页面发给浏览器后便销毁掉刚才创建的页面对象, 服务器无法为客户端保存任何信息. 当客户端浏览器发送POST请求时, 由客户端浏览器提供自己的参数并传到服务器端, 服务器做的工作和第一次GET请求时并没有区别, 只是客户端通过某种手段将自己的状态告诉了服务器, 而这种手段就是状态管理, 由客户端维护状态的状态管理就是客户端状态管理. 而随着技术的发展, 服务器端也可以记录客户的状态信息, 称之为服务器状态管理. 总之, 状态管理的目的是保存客户端的参数或状态, 例如: 用户的登陆状态, 由于HTTP协议时无状态的, 当我们第二次请求服务器时, 服务器已经丢掉了之前的页面对象, 服务器无法判断用户是已经登陆的用户还是为登陆的用户, 状态管理就为我们提供了这么一种手段, 用来告诉服务器用户时登陆过的, 还是未登录的.
状态管理的手段有9种: 见下图:
状态管理有基于客户端和基于服务器的两类状态管理, 其中基于客户端的状态管理是指状态管理信息存储在浏览器上, 在各次请求中不会再服务器上维护任何信息; 而基于服务器的状态管理将由服务器存储和维护客户端的状态信息.
基于客户端的状态管理(5种): 隐藏域、视图状态、控件状态、cookie、查询字符串, 其中控件状态多用于控件开发, 网站很少应用.
ViewState: 隐藏域和视图状态常用于同一页面的不同次请求之间的状态管理:
Name属性对客户端控件很重要, 添加了”name”属性后, name的值将会发送到服务器. 在Get或Post请求中, 将以"name属性的值"="value属性的值"发送, 多个名值对用&隔开.
//Calendar.aspx
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
Inherits="Calendar"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>My Calendar</title>
<style type="text/css">
.currentdate
{
border: solid 1px Black;
background-color: Aqua;
color: Fuchsia;
}
table
{
border-collapse: collapse;
border: solid 1px Green;
}
td
{
padding: 15px;
text-align: center;
border: solid 1px Green;
border-collapse: collapse;
}
.haveEvent
{
background-image: url(images/tips.gif);
background-repeat: no-repeat;
background-position: right bottom;
}
</style>
</head>
<body>
<form id="form_calendar" runat="server">
<div>
<div style="float:left">
<asp:Button ID="btn_previous" runat="server" Text="上一月" OnClick="Btn_Previous_Click"/>
<asp:Label ID="lbl_currentdate" runat="server" Text="当前日期"></asp:Label>
<asp:LinkButton ID="lbtn_today" runat="server" OnClick="lbtn_today_Click">今天</asp:LinkButton>
<asp:Button ID="btn_next" runat="server" Text="下一月" OnClick="Btn_Next_Click"/>
<br />
<br />
<asp:Table ID="tb_calendar" runat="server">
</asp:Table>
<br />
标题:
<asp:TextBox ID="txt_title" Width="280px" runat="server"></asp:TextBox><br /><br/>
内容:
<asp:TextBox ID="txt_content" Width="280px" runat="server" TextMode="MultiLine"
Height="100px"></asp:TextBox>
<br /><br />
<asp:LinkButton ID="lbtn_add" runat="server" onclick="lbtn_add_Click">添加</asp:LinkButton>
</div>
<div style="float:right; width:299px;">
事件列表:
<asp:BulletedList ID="btl_Title" runat="server" Height="22px" Width="256px">
</asp:BulletedList>
<asp:ListBox ID="lst_content" runat="server" Height="100px" Width="301px"></asp:ListBox>
</div>
</div>
<asp:HiddenField ID="hid_currentdate" runat="server"/>
</form>
</body>
</html>
//Calendar.aspx.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
publicpartialclass Calendar : System.Web.UI.Page
{
#region 全局变量
//private DateTime _current;
public DateTime CurrentDate
{
#region 普通属性
/*
get
{
return this._current;
}
set
{
this._current = value;
}
* */
#endregion
#region 属性直接存取ViewState
get
{
if (this.IsPostBack)
{
return (DateTime)this.ViewState["currentdate"];
}
else
{
return DateTime.Now;
}
}
set
{
this.ViewState["currentdate"] = value;
}
#endregion
}
#endregion
#region 页面事件
protectedvoid Page_PreInit(object sender, EventArgs e)
{
#region 隐藏域
/*
string currentdate = this.Request[this.hid_currentdate.ClientID]; //直接用隐藏域的ID值("hid_currentdate")做索引也可
//隐藏域最早可以在PreInit事件中处理(从Request中取), 但如果通过隐藏域的.Value属性取值必须在InitComplete之后
if (!string.IsNullOrEmpty(currentdate))
{
this.CurrentDate = DateTime.Parse(currentdate);
}
else
{
this.CurrentDate = DateTime.Now;
}
*/
#endregion
}
protectedvoid Page_PreLoad(object sender, EventArgs e)
{
/*
#region ViewSate
if (this.IsPostBack)
{
this.CurrentDate = (DateTime)this.ViewState["currentdate"];
}
else
{
this.CurrentDate = DateTime.Now;
}
#endregion
*/
}
protectedvoid Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
//画表格
//this._current = DateTime.Now;
this.CurrentDate = DateTime.Now;
//ShowCalendar();
//this.lbl_test.Text = Day1ofMonth.ToString();
}
ShowCalendar();
}
#endregion
#region 通过属性存取视图状态, 不再需要PreRenderComplete事件
/*
//保存数据岛隐藏域
protected void Page_PreRenderComplete(object sender, EventArgs e)
{
//this.hid_currentdate.Value = this.CurrentDate.ToShortDateString();
this.ViewState["currentdate"] = this.CurrentDate;
}
#endregion
* */
#endregion
privatevoid ShowCalendar()
{
//清楚数据
this.tb_calendar.Rows.Clear();
this.lbl_currentdate.Text =this.CurrentDate.ToShortDateString(); //lbl始终显示当前日期
//this.txt_title.Text = "";
//this.txt_content.Text = "";
this.btl_Title.Items.Clear();
this.lst_content.Items.Clear();
//日历数据
int day1ofMonth = (int)new DateTime(this.CurrentDate.Year, this.CurrentDate.Month, 1).DayOfWeek; //每月1号星期几, 返回值为枚举需强转
int dayofMonth = DateTime.DaysInMonth(this.CurrentDate.Year, this.CurrentDate.Month); //每月有多少天
//画日历
string[] weekname =newstring[7] { "日", "一", "二", "三", "四", "五", "六" };
int rows = (day1ofMonth + dayofMonth +6) /7;
for (int i =0; i <= rows; i++)
{
TableRow tr =new TableRow();
this.tb_calendar.Rows.Add(tr);
if (i ==0) //第一行, 填入星期几
{
for (int j =0; j < weekname.Length; j++)
{
TableCell tc =new TableCell();
tr.Cells.Add(tc);
tc.Text = weekname[j];
if (j ==0|| j ==6)
{
tc.ForeColor = System.Drawing.Color.Red;
}
else
{
//nothing to do here!
}
}
}
else//填入空白格
{
for (int j =0; j <7; j++)
{
TableCell tc =new TableCell();
tr.Cells.Add(tc);
//以下三行为每次的清理操作
//tc.ForeColor = System.Drawing.Color.Black; //每次清除前景色, 可以用样式表实现
//tc.BackColor = System.Drawing.Color.White; //每次清楚背景色
tc.Text =" "; //每次画表格前, 清除原先的数字
}
}
}
//填数据
string virtualPath =this.Server.MapPath("~/App_Data");
int rowindex;
int colindex;
for (int i =1; i <= dayofMonth; i++)
{
rowindex = (day1ofMonth + i -1) /7+1; //取得行索引
colindex = (day1ofMonth + i -1) %7; //取得列索引
TableCell tc =this.tb_calendar.Rows[rowindex].Cells[colindex];
//tc.Text = i.ToString();
LinkButton lbtn =new LinkButton();
lbtn.ID =string.Format("lbtn{0}",i);
lbtn.Text = i.ToString();
lbtn.Click +=new EventHandler(lbtn_Click); //添加天按钮的事件
//用命令参数, 可以获得选中按钮所对应的日期是什么
//lbtn.CommandArgument = new DateTime(this.CurrentDate.Year, this.CurrentDate.Month, i).ToShortDateString();
tc.Controls.Add(lbtn);
if (i ==this.CurrentDate.Day)
{
//tc.ForeColor = System.Drawing.Color.Magenta;
//tc.BackColor = System.Drawing.Color.Cyan;
//lbtn.CssClass = "currentdate"; //引用Css样式, 在aspx中添加.currentdate{}样式
lbtn.CssClass ="currentdate";
}
else
{
//nothing to do here!
}
//产看文件夹中是否有记录事情的文件, 有的话则改变图标
string filedir = System.IO.Path.Combine(virtualPath, new DateTime(this.CurrentDate.Year,this.CurrentDate.Month,i).ToShortDateString()); //this.CurrentDate一定有值
System.IO.DirectoryInfo dirinfo =new System.IO.DirectoryInfo(filedir);
if (dirinfo.Exists)
{
System.IO.FileInfo[] files = dirinfo.GetFiles();
if (files.Length >0)
{
tc.CssClass ="haveEvent";
}
else
{
this.btl_Title.Items.Clear();
}
}
else
{
//nothing to do here!
}
}
this.lbl_currentdate.Text =this.CurrentDate.ToShortDateString(); //填充当前日期
//产看当日的文件夹中是否有记录事情的文件, 有的话则显示
string filedir2 = System.IO.Path.Combine(virtualPath, this.CurrentDate.ToShortDateString()); //this.CurrentDate一定有值
System.IO.DirectoryInfo dirinfo2 =new System.IO.DirectoryInfo(filedir2);
if (dirinfo2.Exists)
{
System.IO.FileInfo[] files = dirinfo2.GetFiles();
if (files.Length >0)
{
string title ="";
string content ="";
System.IO.StreamReader sr =null;
foreach (System.IO.FileInfo fi in files)
{
sr =new System.IO.StreamReader(fi.FullName);
title = sr.ReadLine();
content = sr.ReadLine();
sr.Close();
this.btl_Title.Items.Add(title);
this.lst_content.Items.Add(content + Environment.NewLine);
}
}
else
{
this.btl_Title.Items.Clear();
}
}
else
{
//nothing to do here!
}
}
#region 按钮事件
protectedvoid Btn_Previous_Click(object sender, EventArgs e)
{
this.CurrentDate =this.CurrentDate.AddMonths(-1);
ShowCalendar();
}
protectedvoid Btn_Next_Click(object sender, EventArgs e)
{
this.CurrentDate =this.CurrentDate.AddMonths(1);
ShowCalendar();
}
void lbtn_Click(object sender, EventArgs e)
{
LinkButton lbtn = sender as LinkButton;
int day = Convert.ToInt32(lbtn.Text);
this.CurrentDate =new DateTime(this.CurrentDate.Year, this.CurrentDate.Month, day);
ShowCalendar();
}
protectedvoid lbtn_today_Click(object sender, EventArgs e)
{
this.CurrentDate = DateTime.Now;
ShowCalendar();
}
protectedvoid lbtn_add_Click(object sender, EventArgs e)
{
string virtualPath =this.Server.MapPath("~/App_Data");
string filedir = System.IO.Path.Combine(virtualPath, this.CurrentDate.ToShortDateString()); //this.CurrentDate一定有值
System.IO.DirectoryInfo dirinfo =new System.IO.DirectoryInfo(filedir);
if (!dirinfo.Exists)
{
dirinfo.Create();
}
else
{
//nothing to do here!
}
if (this.txt_title.Text !=""&&this.txt_content.Text !="")
{
System.IO.StreamWriter sw =new System.IO.StreamWriter(string.Format("{0}/{1}", filedir,System.IO.Path.GetRandomFileName()));
sw.WriteLine(txt_title.Text);
sw.WriteLine(txt_content.Text);
sw.Close();
this.txt_title.Text ="";
this.txt_content.Text ="";
}
else
{
//nothing to do here!
}
ShowCalendar();
}
#endregion
}
Cookie:
Cookie的使用:
发送到客户端的Cookie信息需要通过键值对处理, 且键和值的类型均为string.
大多数浏览器Cookie中保存的Value长度不能超过2K.
默认情况下, 关闭浏览器后Cookie将一同消失, 如果需要长时间保存Cookie, 可以修改Cookie的过期时间(Expires), 而删除Cookie的操作为设置一个更早的已失效的过期时间.
//CookieDemo.aspx
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="txt_input" runat="server"></asp:TextBox>
<asp:LinkButton ID="lbtn_save" runat="server" onclick="lbtn_save_Click">保存</asp:LinkButton>
<asp:CheckBox ID="chk_cookie" runat="server" Text="长期有效"/>
<asp:LinkButton ID="lbtn_del" runat="server" onclick="lbtn_del_Click">删除</asp:LinkButton>
<hr />
<asp:TextBox ID="txt_result" runat="server"></asp:TextBox>
<asp:LinkButton ID="lbtn_get" runat="server" onclick="lbtn_get_Click">获取</asp:LinkButton>
</div>
</form>
</body>
//CookieDemo.aspx.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
publicpartialclass _Default : System.Web.UI.Page
{
protectedvoid Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
}
}
protectedvoid lbtn_save_Click(object sender, EventArgs e)
{
//创建cookie对象
HttpCookie cookie =new HttpCookie("CK");
cookie.Value =this.txt_input.Text;
if (this.chk_cookie.Checked ==true)
{
cookie.Expires = DateTime.Now.AddDays(7);
}
//创建完还要放到Response中去, 生成回应头
//this.Response.SetCookie(cookie); --更新cookie
this.Response.Cookies.Add(cookie);
}
protectedvoid lbtn_get_Click(object sender, EventArgs e)
{
HttpCookie hc =this.Request.Cookies["CK"];
this.txt_result.Text = hc.Value.ToString();
}
protectedvoid lbtn_del_Click(object sender, EventArgs e)
{
HttpCookie hc =this.Request.Cookies["CK"];
hc.Expires =new DateTime(1900, 1, 1);
this.Response.Cookies.Add(hc);
}
}
查询字符串:
示例: http://www.cait.com/default..aspx?category=teacher&name=hao
大多数浏览器允许的URL长度不大于2K
若使用查询字符串, 必须使用HttpGet命令提交, 注意这种方式不适合传递重要的敏感信息
//default.aspx, 注意地址栏
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
栏目:<asp:TextBox ID="txt_category" runat="server"></asp:TextBox>
姓名:<asp:TextBox ID="txt_name" runat="server"></asp:TextBox>
<hr />
<asp:LinkButton ID="lbtn_submit" runat="server" onclick="lbtn_submit_Click">查看</asp:LinkButton>
</div>
</form>
</body>
</html>
//default.aspx.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
publicpartialclass _Default : System.Web.UI.Page
{
protectedvoid Page_Load(object sender, EventArgs e)
{
}
protectedvoid lbtn_submit_Click(object sender, EventArgs e)
{
if (this.txt_category.Text !=null&&this.txt_name.Text !=null)
{
string url =string.Format("default.aspx?category={0}&name={1}",this.txt_category.Text,this.txt_name.Text);
this.Response.Redirect(url);
//this.Server.Transfer(url);
}
}
}
会话状态Session:
Session是一种将用户状态信息保存在服务器上的机制. 当用户第一次请求(GET)服务器时, 服务器将为客户端创建一个SessionID并发给客户端(通常存在cookie中), 同时在服务器内存上为客户端创建一个字典用来保存客户端信息. 当用户第二次请求时(POST)将自动把SessionID通过请求参数传给服务器, 从而判断用户的状态.
默认情况下, *.aspx文件支持Session, 而*.ashx不支持Session. 因此ashx要使用Session需要实现System.Web.SessionState.IRequiresSessionState
Session的实现机制较复杂, 但使用起来确很简单:
存: this.Session[“键”] = 值; 取: object obje = this.Session[“键”];
客户端: SessionID可以存在Cookie(默认)或Url中, 若客户端禁用cookie, 那么可以在配置文件中稍作修改就可以将SessionID存于Url中.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<system.web>
<sessionState cookieless = “true” />
</system.web>
</configuration>
服务器端: 存储客户端的状态信息, 可采用多种方式存储.
1.存放在服务器内存中, 也就是存放在为IIS进程所分配的内存中, 如果Web服务器进程崩溃将会丢失会话信息. 因为服务器内存资源有限, 所以服务器会给Session设置一个过期时间, 当过期时间满后如果客户仍然没有再次访问服务器, 则会删除相应的用户字典. 这个机制成为滑动过期机制, 可以再配置文件中修改该时间.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<system.web>
<sessionState mode=”Inproc” /><!—mode=”off”表示禁用Session-->
</system.web>
</configuration>
2.存放在StateServer中, 使用该种方式可以在网站崩溃情况下, 保持Session信息. 该种设置需要配置stateConnectionString(默认: tcpip=127.0.0.1:42424), ip地址可以不同, 但是端口号必须相同. 此外, 还需要确保”服务管理器”中的ASP.NET State Service服务必须启动.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<system.web>
<sessionState mode=”StateServer” stateConnectionString=”tcpip=127.0.0.1:42424”/>
</system.web>
</configuration>
3.存放在SqlServer中, 使用该种方式, 需要使用Aspnet_regsql.exe(路径: C:\windows\Mcrosoft.NET\Framework\v2.0.50717)工具安装会话状态数据库, 命令操作: “aspnet_regsql –E –ssadd –sstype p”; 手动操作: 在Aspnet_regsql.exe工具目录下, 双击执行并选中sql脚本installsqlstate.sql(临时表)或者installpersistsqlstate(永久表).
同时还要修改配置文件: 配置连接串, 配置数据库的超时时间(默认30秒), 且需要确保Session中的对象是可序列化的.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<system.web>
<sessionState mode=”SQLServer” timeout=”60” sqlConnectionString=”data source=.\;integrated Security=sspi”/>
</system.web>
</configuration>
4. 最后一种为自定义的状态管理机制, 该种机制需要创建一个集成SessionStateStoreProviderBase抽象类的类, 然后在配置文件中指定实现类的类名.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<system.web>
<sessionState mode=”Custom” customProvider=”namespace.classname,assembl”/>
</system.web>
</configuration>
//default.aspx
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<br />
<br />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:LinkButton ID="LinkButton1" runat="server" onclick="LinkButton1_Click">保存</asp:LinkButton>
<br />
<br />
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<asp:LinkButton ID="LinkButton2" runat="server" onclick="LinkButton2_Click">获取</asp:LinkButton>
</div>
</form>
</body>
</html>
//default.aspx.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
publicpartialclass _Default : System.Web.UI.Page
{
protectedvoid Page_Load(object sender, EventArgs e)
{
}
protectedvoid LinkButton1_Click(object sender, EventArgs e)
{
this.Session["Code"] =this.TextBox1.Text;
}
protectedvoid LinkButton2_Click(object sender, EventArgs e)
{
this.Label1.Text =this.Session["Code"] asstring;
}
}
Application:
Application是全局的状态管理手段, 当服务器一启动时Application就会被创建并长期存在于服务器上, Appllication类似于服务器的ViewState, 但只有一份而且没有过期时间, Application是全局的, 而ViewState是页面级的, Application中保存的信息持久有效, 且数据保存在一个全局的字典中. Application允许多线程操作, HttpApplicationState对象提供了Lock()和UnLock()两个方法提供同步的访问. 我们可以通过Global.asax文件中的Application_Start()方法来初始化应用程序状态Application. 注意: 这里的Application不同于HttpApplication类(处理管道).
Application适合存储全局性的数据, 如: 当前在线人数, 当前系统运行时间等.
//default.aspx
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lbl_time" runat="server" Text="页面执行时间"></asp:Label>
</div>
</form>
</body>
</html>
//default.aspx.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
publicpartialclass _Default : System.Web.UI.Page
{
protectedvoid Page_Load(object sender, EventArgs e)
{
}
protectedvoid Page_PreRenderComplete(object sender, EventArgs e)
{
DateTime old = DateTime.Parse(this.Application["AppStartTime"].ToString());
TimeSpan span = DateTime.Now - old;
this.lbl_time.Text =string.Format("服务器累计运行时间: {0}毫秒! ", span.TotalMilliseconds);
}
}
//Global.asax
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
this.Application["AppStartTime"] = DateTime.Now;
}
void Application_End(object sender, EventArgs e)
{
// Code that runs on application shutdown
}
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
}
void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started
}
void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends.
// Note: The Session_End event is raised only when the sessionstate mode
// is set to InProc in the Web.config file. If session mode is set to StateServer
// or SQLServer, the event is not raised.
}
</script>
配置文件属性: 配置文件中的Profile, 需要配合Sql Server及个性化数据使用(Profile Provider), 也可以自己实现SqlProfileProvider类将数据保存在XML文件或Web服务中.
ASP.NET 2.0 提供了一个称为个性化数据的功能, 可让您存储特定于用户的数据. 该功能与会话状态类似, 但不同点在: 用户会话过期后, 数据不一定丢失而由应用程序决定. 个性化数据可以让你轻松的管理用户信息, 甚至无需维护自己的数据库, 并且由于个性化数据没有存储到应用程序中, 所以当IIS崩溃、重启等情况时, 数据仍能得到保持.
请求处理的环境HttpContext: 详情可参见HttpApplication处理管道
每当一个请求到达ASP.NET网站时, HttpRuntime将会为这次请求创建一系列的对象, 为了方便使用, HttpRuntime创建一个HttpContext上下文对象(环境对象), 该对象是一个容器对象, 其中定义了用来表示处理此次请求所需要的所有数据. 在一次请求处理过程中, HttpContext对象是贯穿整个请求处理过程的, 因此可用来实现一次请求过程中的状态管理. HttpContext中常用的属性有: Request、Response、Server、Session.
HttpContent对象通过Items属性提供一个基于键值对的状态管理机制, 其中键和值均为Object类型.
Http只能处理一次请求过程, HttpContext是在HttpApplication处理管道中重要的状态管理手段.
//default.aspx
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lbl_time" runat="server" Text="页面事件事件"></asp:Label>
</div>
</form>
</body>
</html>
//default.aspx.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
publicpartialclass _Default : System.Web.UI.Page
{
protectedvoid Page_PreInit(object sender, EventArgs e)
{
//this.Context.Items["time"] = DateTime.Now;
HttpContext.Current.Items["time"] = DateTime.Now; //使用HttpContext类的静态属性
}
protectedvoid Page_Load(object sender, EventArgs e)
{
}
protectedvoid Page_PreRenderComplete(object sender, EventArgs e)
{
TimeSpan span = DateTime.Now - DateTime.Parse(this.Context.Items["time"].ToString());
this.Context.Items["totaltime"] = span.TotalMilliseconds;
this.lbl_time.Text ="11个页面处理事件共耗时(毫秒):"+this.Context.Items["totaltime"].ToString();
}
}
还有个Cache做状态管理, Cache仅有一份, 并且在有请求时, 我们可以通过HttpContext.Current.Cache获得Cache的引用; 无请求时通过HttpRuntime.Cache获得Cache的引用. 我个人感觉Cache主要用于缓存数据, 提供高性能、高效率的使用体验. 当然Cache也可以作为传递状态的一种方式, 因为Cache首先是一种状态管理的手段, 并且是综合Session和Application二者优点的状态管理手段. 稍后, 关于缓存会写一篇博客, 届时在谈谈个人关于Cache的理解吧.
//综合练习: 验证码
//SqlCalendar\DAL\CalendarHelper
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DAL
{
publicclass CalendarHelper //为DAL层提供连接串
{
privatestaticreadonlystring connectionStr = System.Configuration.ConfigurationManager.ConnectionStrings["MsSql"].ConnectionString;
publicstaticstring ConnectionString //对外提供连接串
{
get
{
return connectionStr;
}
}
}
}
//SqlCalendar\DAL\CalendarUser
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DAL
{
publicclass CalendarUser //DAL层通过SqlHelper访问数据库
{
//CalendarUser类提供关于日历用户的功能, 如: 创建用户
//DateTime是值类型, 而值类型没有与Sql中Null的对应, 加?表示可空类型, 即允许值类型为空
publicint CreateUser(string username, string userpass, string email, DateTime? birthday)
{
int result =-1;
//定制的参数是根据SqlHelper的方法来选的
string connectionStr = CalendarHelper.ConnectionString;
string sqlText =@"insert into T_UserInfo(username, userpass,email,birthday)
values(@username,@userpass,@email,@birthday)";
System.Data.CommandType cmdType = System.Data.CommandType.Text;
System.Data.SqlClient.SqlParameter p_username =new System.Data.SqlClient.SqlParameter("@username", System.Data.SqlDbType.NVarChar);
System.Data.SqlClient.SqlParameter p_userpass =new System.Data.SqlClient.SqlParameter("@userpass",System.Data.SqlDbType.NVarChar);
System.Data.SqlClient.SqlParameter p_email =new System.Data.SqlClient.SqlParameter("@email", System.Data.SqlDbType.NVarChar);
System.Data.SqlClient.SqlParameter p_birthday =new System.Data.SqlClient.SqlParameter("@birthday",System.Data.SqlDbType.DateTime);
p_username.Value = username;
p_userpass.Value = userpass;
p_email.Value = email;
p_birthday.Value = birthday;
System.Data.SqlClient.SqlParameter[] paras
=new System.Data.SqlClient.SqlParameter[] { p_username, p_userpass, p_email, p_birthday };
result = Microsoft.ApplicationBlocks.Data.SqlHelper.ExecuteNonQuery(connectionStr, cmdType,sqlText, paras);
return result;
}
publicint CreateUserByProc(string username, string userpass, string email, DateTime? birthday)
{
//定制的参数是根据SqlHelper的方法来选的
string connectionStr = CalendarHelper.ConnectionString;
string sqlText ="SP_CreateUserProc";
System.Data.CommandType cmdType = System.Data.CommandType.StoredProcedure;
System.Data.SqlClient.SqlParameter p_username =new System.Data.SqlClient.SqlParameter("@username", System.Data.SqlDbType.NVarChar);
System.Data.SqlClient.SqlParameter p_userpass =new System.Data.SqlClient.SqlParameter("@userpass", System.Data.SqlDbType.NVarChar);
System.Data.SqlClient.SqlParameter p_email =new System.Data.SqlClient.SqlParameter("@email", System.Data.SqlDbType.NVarChar);
System.Data.SqlClient.SqlParameter p_birthday =new System.Data.SqlClient.SqlParameter("@birthday", System.Data.SqlDbType.DateTime);
System.Data.SqlClient.SqlParameter p_return =new System.Data.SqlClient.SqlParameter("@returnValue",System.Data.SqlDbType.Int);
p_username.Value = username;
p_userpass.Value = userpass;
p_email.Value = email;
p_birthday.Value = birthday;
p_return.Direction = System.Data.ParameterDirection.ReturnValue;
System.Data.SqlClient.SqlParameter[] paras
=new System.Data.SqlClient.SqlParameter[] { p_username, p_userpass, p_email, p_birthday,p_return};
Microsoft.ApplicationBlocks.Data.SqlHelper.ExecuteNonQuery(connectionStr, cmdType, sqlText, paras);
//执行完存储过程后, 获取返回值
return (int)p_return.Value;
}
}
}
//SqlCalendar\SqlHelper --- 网上可以下载到
//SqlCalendar\Validator\Default.aspx
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
<style type="text/css">
.style1
{
width: 95%;
height: 216px;
}
.style5
{
}
.style6
{
width: 57px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div style="text-align:center;">
<div style=" width: 500px; height:500px; background-color:Silver; text-align:left; margin-top: 20; padding: 10px 0px 0px 30px; margin-top:4%">
<table class="style1">
<tr>
<td class="style6">
<label for="txt_username">用户名: </label>
</td>
<td class="style5">
<asp:TextBox ID="txt_username" runat="server" Width="209px"></asp:TextBox>
</td>
<td>
<asp:RequiredFieldValidator ID="validator_rqeField_username" runat="server"
ControlToValidate="txt_username" Display="Dynamic" ErrorMessage="用户名不能为空"></asp:RequiredFieldValidator>
<asp:CustomValidator ID="validator_custom_username" runat="server"
ErrorMessage="用户名已存在" ControlToValidate="txt_username"></asp:CustomValidator>
</td>
</tr>
<tr>
<td class="style6">
<label for="txt_password">密 码: </label>
</td>
<td class="style5">
<asp:TextBox ID="txt_password" runat="server" Width="209px" TextMode="Password"></asp:TextBox>
</td>
<td>
<asp:RequiredFieldValidator ID="validator_rqeField_password" runat="server"
ControlToValidate="txt_password" ErrorMessage="密码不能为空"></asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td class="style6">
<label for="txt_confirm">确 认: </label>
</td>
<td class="style5">
<asp:TextBox ID="txt_confirm" runat="server" Width="209px" TextMode="Password"></asp:TextBox>
</td>
<td>
<asp:RequiredFieldValidator ID="validator_rqe_confirm" runat="server"
Display="Dynamic" ErrorMessage="确认密码不能为空" ControlToValidate="txt_confirm"></asp:RequiredFieldValidator>
<asp:CompareValidator ID="validator_compto_conpass" runat="server"
ControlToCompare="txt_password" ControlToValidate="txt_confirm"
Display="Dynamic" ErrorMessage="密码不一致"></asp:CompareValidator>
</td>
</tr>
<tr>
<td class="style6">
<label for="txt_email">邮 箱: </label>
</td>
<td class="style5">
<asp:TextBox ID="txt_email" runat="server" Width="209px"></asp:TextBox>
</td>
<td>
<asp:RequiredFieldValidator ID="validator_rqeField_email" runat="server"
ControlToValidate="txt_email" Display="Dynamic" ErrorMessage="邮箱不能为空"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="validator_regx_email" runat="server"
ControlToValidate="txt_email" Display="Dynamic" ErrorMessage="邮件格式错误"
ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*"></asp:RegularExpressionValidator>
</td>
</tr>
<tr>
<td class="style6">
<label for="txt_birth">生 日: </label>
</td>
<td class="style5">
<asp:TextBox ID="txt_birth" runat="server" Width="209px"></asp:TextBox>
</td>
<td>
<asp:RangeValidator ID="validator_range_birth" runat="server"
ControlToValidate="txt_birth" ErrorMessage="日期格式错误" Type="Date"></asp:RangeValidator>
</td>
</tr>
<tr>
<td class="style6">
验证码:
</td>
<td class="style5" colspan="2">
<asp:Image ID="Image1" runat="server" ImageUrl="~/DynamicCode.ashx"/>
</td>
</tr>
<tr>
<td class="style6">
输入验证码:</td>
<td class="style5" colspan="2">
<asp:TextBox ID="txt_dcode" runat="server" Width="210px"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server"
ErrorMessage="验证码不能为空" Display="Dynamic" ControlToValidate="txt_dcode"></asp:RequiredFieldValidator>
<asp:CustomValidator ID="Validator_Dcode" runat="server"
ErrorMessage="验证码错误" ControlToValidate="txt_dcode" Display="Dynamic"
onservervalidate="Validator_Dcode_ServerValidate"></asp:CustomValidator>
</td>
</tr>
<tr>
<td colspan="3">
<asp:LinkButton ID="lbtn_reguser" runat="server" onclick="lbtn_reguser_Click">注 册</asp:LinkButton>
<asp:LinkButton ID="ltbn_forgetpass" runat="server">忘记密码?</asp:LinkButton>
</td>
</tr>
</table>
</div>
</div>
</form>
</body>
</html>
//SqlCalendar\Validator\Default.aspx.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
publicpartialclass _Default : System.Web.UI.Page
{
protectedvoid Page_Init(object sender, EventArgs e)
{
this.validator_range_birth.MaximumValue = DateTime.Now.ToShortDateString();
this.validator_range_birth.MinimumValue = DateTime.Now.AddYears(-150).ToShortDateString();
}
protectedvoid Page_Load(object sender, EventArgs e)
{
if (this.IsPostBack)
{
//this.Validate(); //手动调用验证方法
}
}
protectedvoid lbtn_reguser_Click(object sender, EventArgs e)
{
if (this.IsValid) //当所有页面对象验证通过后, 将设置Page的IsValid属性, 支出验证通过
{
DAL.CalendarUser calendaruser =new DAL.CalendarUser();
//初始birthday为空, 当串不为空时转换
DateTime? birthday =null;
if (!string.IsNullOrEmpty(this.txt_birth.Text))
{
birthday = DateTime.Parse(this.txt_birth.Text);
}
//int a = calendaruser.CreateUser(this.txt_username.Text, this.txt_password.Text, this.txt_email.Text, birthday);
int exist = calendaruser.CreateUserByProc(this.txt_username.Text, this.txt_password.Text, this.txt_email.Text, birthday);
if (exist !=0)
{
this.validator_custom_username.IsValid =false;
}
}
}
protectedvoid Validator_Dcode_ServerValidate(object source, ServerValidateEventArgs args)
{
//每次复位Validator状态
args.IsValid =false;
//this.Validator_Dcode.IsValid = false;
#region Cookie
//HttpCookie hc = this.Request.Cookies["Dcode"];
//if (hc != null)
//{
// string rqtcode = hc.Value.ToString();
////if(rqtcode == args.Value)
// if (rqtcode == this.txt_dcode.Text)
// {
////this.Validator_Dcode.IsValid = true; //this.Validator_Dcode.IsValid是Valid控件上的IsValid
// args.IsValid = true; //这里必须用args.IsValid, 因为args.IsValid是事件参数(临时的), 最终他会根据事件参数的结果修改控件上的IsValid属性, 进而显示错误信息
// }
//}
//else
//{
// this.validator_dcode.isvalid = false;
//}
#endregion
#region Session
if (this.Session["Dycode"] !=null)
{
string num =this.Session["Dycode"] asstring;
if (num ==this.txt_dcode.Text)
{
args.IsValid =true;
//this.Validator_Dcode.IsValid = true;
}
else
{
args.IsValid =false;
//this.Validator_Dcode.IsValid = false;
}
}
#endregion
}
}
//SqlCalendar\Validator\DynamicCode.ashx
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System;
using System.Web;
//使用Session记得在ashx中, 添加IRequiresSessionState的接口, 而aspx文件默认就是支持的
publicclass DynamicCode : IHttpHandler,System.Web.SessionState.IRequiresSessionState {
publicvoid ProcessRequest (HttpContext context) {
//context.Response.ContentType = "text/plain";
//context.Response.Write("Hello World");
context.Response.ContentType ="image/jpeg";
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
//随机数生成器
Random ran =new Random();
int rannum = ran.Next(10000, 100000);
//创建位图文件
System.Drawing.Bitmap bitmap =new System.Drawing.Bitmap(300, 80);
//在位图文件上画画, 需要创建与图片画板相关的画图器
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
{
//用Graphic对象清空背景
g.Clear(System.Drawing.Color.DarkGreen);
//花矩形框
g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Brushes.Blue,3),0,0,bitmap.Width-1,bitmap.Height-1);
//StringFormat对象, 用来保存数字位置, 在数字矩形的绘图区域中
System.Drawing.StringFormat sf =new System.Drawing.StringFormat();
sf.Alignment = System.Drawing.StringAlignment.Center;
sf.LineAlignment = System.Drawing.StringAlignment.Center;
//画数字, RectangleF用来确定显示数字的矩形区域
g.DrawString(rannum.ToString(),
new System.Drawing.Font("黑体", 50),
System.Drawing.Brushes.Black,
new System.Drawing.RectangleF(0, 0, bitmap.Width, bitmap.Height),
sf);
//画横线
for (int i =0; i <80; i++)
{
g.DrawLine(new System.Drawing.Pen(System.Drawing.Brushes.Black),
ran.Next(0, bitmap.Width),
ran.Next(0, bitmap.Height),
ran.Next(0, bitmap.Width),
ran.Next(0, bitmap.Height));
}
//将数字保存到Cookie中
//HttpCookie hc = new HttpCookie("Dcode");
//hc.Value = rannum.ToString();
//context.Response.Cookies.Add(hc); //保存到cookie中去, 但是没有页面对象, 所以需要通过context
//将数字保存到Session中
context.Session["DyCode"] = rannum.ToString();
}
//保存图片到response, 注意: 这里是一般处理程序, 没有页面对象, 所以只能用context
bitmap.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
}
publicbool IsReusable {
get {
returnfalse;
}
}
}
/// 补充内容
一:页面间通过JS传值的形式大概有三种
1 window.opener传值,子页面能获取父页面的窗口对象。当然就能获取到对象的值了,这种方式不存在传值 的长度限制,不能跨域。
2 cookies传值,传值长度有限制。
3 URL传值,值也是有限制,但是能跨域。
二:ASP.NET页面传值
1. 使用QueryString变量(或者称URL)地址后加“?”
2. Session传值。 (服务端)
3. Applica传值。 (全局的,最好的例子是在线访问量)
4. Cookies传值。(客户端保存)
5 HttpContext 也即是server.transfer() 注意它与redirect的区别
三:jS访问后台变量(1、2使用较多)
1、通过页面上隐藏控件访问 <input id="hidencontrol" type="hidden" runat="server"> (注意要runat=“server”)
2、<%=对象名%> 对象要是pubulic的
3 后台注册函数"<script language='javascript'> value=" + 变量名+ "</script>" 访问value即可
四 :后台访问JS变量
1 同样是hidden
2 cookie或session
五 JS调用后台函数
1 document.getElementById("btn1").click();
2 var f = "<%=function()%>"; alert(f);
六 后台调用JS
1 注册JS函数
2 使用Literal