用户注册、登录和注销这3个功能几乎是每一个网站(或网络应用程序)所必需的功能,特别是网站需要识别用户身份。用户注册可以向用户提供在网站中注册其信息的功能;用户一旦注册之后,该用户可以通过用户登录功能登录到该网站;用户注销向用户提供离开网站的功能,并注销网站识别的当前身份票据。本章将介绍使用ASP.NET 2.0和ASP.NET AJAX技术,以及SQL Server 2005数据库共同实现用户注册、登录和注销的方法。
6.1 用户注册、登录和注销应用程序构成
本节介绍用户注册、登录和注销应用程序AjaxUser的实现原理、组成、配置等。
6.1.1 用户注册、登录和注销实现原理
用户注册、登录和注销应用程序的实现原理比较简单。新用户可以通过注册功能把自己注册成为应用程序的一个合法用户。已注册的用户可以通过登录功能登录到系统中,并使用注销功能退出系统或应用程序。用户注册、登录和注销的原理图如图6.1所示。
|
图6.1 用户注册、登录和注销的原理图
6.1.2 AjaxUser应用程序的组成
用户注册、登录和注销应用程序的名称为AjaxUser,它使用的数据库的名称为AjaxUserDB。在Visual Studio 2005的【解决方案资源管理器】面板中查看该应用程序,如图6.2所示。AjaxUser应用程序的组成元素说明如下:
App_Code文件夹包含了2个类文件:ASPNETAJAXWeb.cs和User.cs,它们分别定义了AjaxUserSystem和User类。
App_Themes文件夹包含了AjaxUser应用程序的主题和样式文件,如web.css、web.skin等。
Bin文件夹包含了AjaxUser应用程序引入的程序集,如AjaxControlToolKit.dll、ASPNETAJAXWeb.ValidateCode.dll等。
Login.aspx页面为用户登录页面,将实现用户登录的功能。
Logoff.aspx页面为用户提供了注销登录的功能。
Register.aspx页面为用户提供了注册页面,该页面能够实现注册新用户的功能。
Web.config文件为AjaxUser应用程序的配置文件,它配置了数据库连接字符串、引用的程序集等属性。

图6.2 在【解决方案资源管理器】面板中查看AjaxUser应用程序
6.1.3 AjaxUser应用程序的配置
AjaxUser应用程序的连接字符串放置在Web.config配置文件的<connectionString>元素中,具体代码如下:
<connectionStrings>
<add name="SQLCONNECTIONSTRING"
connectionString="data source=localhost;user id=sa;pwd=123456;
database=AjaxUserDB"
providerName="System.Data.SqlClient"/>
</connectionStrings>
AjaxUser应用程序在Web.config配置文件的<controls>元素中还配置了与AJAX服务器控件相关的内容,该内容为AjaxControlToolkit.dll程序集中的控件提供了一个前缀字符串“ajaxToolkit”。因此,在该应用程序中的页面引用AjaxControlToolkit.dll程序集中的控件时,不再需要在每一个页面的HTML代码中添加“<Register>”代码,而是直接使用“ajaxToolkit”前缀来引用AjaxControlToolkit.dll程序集中的控件。<controls>元素的具体代码如下:
<controls>
<add namespace="AjaxControlToolkit" assembly="AjaxControlToolkit"
tagPrefix="ajaxToolkit"/>
……
</controls>
6.2 创建图文验证模块
图文验证模块能够以图片的形式输出一个验证码,应用程序可以使用该验证码来避免机器人和程序自动登录应用程序。
本节介绍的图文验证模块包含两部分:ValidateCode类库工程和ValidateCode.aspx页面。其中,ValidateCode类库工程将输出一个名称为ASPNETAJAXWeb.ValidateCode.dll的动态程序集;ValidateCode.aspx页面将使用该程序集产生并输出验证码。
6.2.1 创建ValidateCode类库工程
在Visual Studio 2005集成开发环境中创建ValidateCode类库工程,该工程只包含一个类文件:ValidateCode.cs。在【解决方案资源管理器】面板中查看ValidateCode类库工程,如图6.3所示。下面介绍配置该类库工程的输出文件和默认命名空间的基本方法,其具体步骤如下:
在【解决方案资源管理器】面板中,右键单击【ValidateCode】节点,并选择【属性】命令,操作如图6.4所示。

图6.3 查看ValidateCode类库工程 图6.4 查看ValidateCode类库工程属性的操作
单击【属性】命令,选中【应用程序】选项卡,并分别把程序集名称和默认命名空间两个属性的值设置为“ASPNETAJAXWeb.ValidateCode”和“ASPNETAJAXWeb. ValidateCode.Page”,操作如图6.5所示。
注意:通过上述设置之后,ValidateCode类库工程生成之后,将创建一个程序集,该程序集的名称为ASPNETAJAXWeb.ValidateCode.dll。
ValidateCode.cs类文件定义了ValidateCode类,引入了6个命名空间。其中,该类被包含在ASPNETAJAXWeb.ValidateCode.Page命名空间中,且直接继承于System.Web.UI.Page类。其程序代码如下:

图6.5 设置ValidateCode类库的程序集名称和默认命名空间
using System;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;
namespace ASPNETAJAXWeb.ValidateCode.Page
{
public class ValidateCode:System.Web.UI.Page
{
……
}
}
在下述程序代码中,ValidateCode类声明了7个字段(IMAGELENGTHBASE、IMAGEHEIGTH、IMAGELINENUMBER、IMAGEPOINTNUMBER、length、code和VALIDATECODEKEY)和2个属性(Length和Code)。其中,Length属性获取和设置验证码的长度,即字符的数量;Code属性获取验证码。
private const double IMAGELENGTHBASE = 12.5;
private const int IMAGEHEIGTH = 22;
private const int IMAGELINENUMBER = 25;
private const int IMAGEPOINTNUMBER = 100;
public static string VALIDATECODEKEY = "VALIDATECODEKEY";
private int length = 4;
private string code = string.Empty;
/// <summary>
/// 获取或设置验证码长度,默认值为4
/// </summary>
public int Length
{
get{return length;}
set{length = value;}
}
/// <summary>
/// 获取验证码
/// </summary>
public string Code
{
get{return Code;}
}
public ValidateCode()
{
}
……
6.2.2 创建随机数字串
在下述程序代码中,CreateCode(int length)方法将创建一个由数字组成的、指定长度(由length参数指定)的随机字符串。CreateCode(int length)方法首先创建一个随机对象random,并根据指定的长度,使用for语句创建一个随机数字字符串。最后,将该随机数字字符串保存在Session对象中。
/// <summary>
/// 创建随机验证码
/// </summary>
/// <param name="length">验证码长度</param>
/// <returns></returns>
public string CreateCode(int length)
{
if(length <= 0) return string.Empty;
///创建一组随机数,并构成验证码
Random random = new Random();
StringBuilder sbCode = new StringBuilder();
for(int i = 0; i < length; i++)
{
sbCode.Append(random.Next(0,10));
}
///保存验证码到Session对象中
code = sbCode.ToString();
Session[VALIDATECODEKEY] = code;
return code;
}
6.2.3 绘制带有文字的图像
绘制带有文字的图像由CreateValidateImage(string code)方法实现。其中,code参数指定被输出的随机字符串,即验证图片中显示的文本。CreateValidateImage(string code)方法绘制带有文字的图像的具体步骤如下:
判断验证码的合法性,如果为空,则中止该方法。程序代码如下:
/// <summary>
/// 创建验证码的图片和验证码
/// </summary>
/// <param name="code">验证码</param>
public void CreateValidateImage(string code)
{
if(string.IsNullOrEmpty(code) == true) return;
///保存验证码到Session对象中
Session[VALIDATECODEKEY] = code;
根据验证码的长度创建一个Bitmap类型的图像image,同时获取该图像的Graphics对象g。
///创建一个图像
Bitmap image = new Bitmap(
(int)Math.Ceiling((code.Length * IMAGELENGTHBASE)),
IMAGEHEIGTH);
Graphics g = Graphics.FromImage(image);
创建一个随机数生成对象random,并先清空图像的背景颜色,然后指定图像的背景颜色为白色。使用for语句在image图像上绘制干扰线。
///随机数生成器
Random random = new Random();
try
{ ///清空图像,并指定填充颜色
g.Clear(Color.White);
///绘制图片的干扰线
int x1,x2,y1,y2;
for(int i = 0; i < IMAGELINENUMBER; i++)
{
x1 = random.Next(image.Width);
y1 = random.Next(image.Height);
x2 = random.Next(image.Width);
y2 = random.Next(image.Height);
///绘制干扰线
g.DrawLine(new Pen(Color.Silver),x1,y1,x2,y2);
}
在image图像上绘制验证码(即code参数的值),并设置绘制的画笔的格式为粗体和斜体。
///绘制验证码
Font font = new Font("Tahoma",
12,FontStyle.Bold | FontStyle.Italic);
LinearGradientBrush brush = new LinearGradientBrush(
new Rectangle(0,0,image.Width,image.Height),
Color.Blue,Color.DarkRed,1.2f,true);
g.DrawString(code,font,brush,2.0f,2.0f);
在image图像上绘制前景噪音点。其中,每一个噪音点的起始坐标、颜色都是随机产生的。
///画图片的前景噪音点
int x,y;
for(int i = 0; i < IMAGEPOINTNUMBER; i++)
{
x = random.Next(image.Width);
y = random.Next(image.Height);
///绘制点
image.SetPixel(x,y,Color.FromArgb(random.Next()));
}
将image图像的边框线设置为Silver,然后绘制image图像的边框线。
///画图片的边框线
g.DrawRectangle(new Pen(Color.Silver),
0,
0,
image.Width - 1,
image.Height - 1);
创建MemoryStream对象ms,并将image图像保存到ms中,同时设置图像保存的格式为Gif。
///保存图片的内容到流中
MemoryStream ms = new MemoryStream();
image.Save(ms,ImageFormat.Gif);
首先设置页面的输出格式为“image/Gif”,然后使用页面的Response对象输出保存在ms对象中图像的二进制数据。其中,输出数据的方法为BinaryWrite()方法。
///输出图片
Response.ClearContent();
Response.ContentType = "image/Gif";
Response.BinaryWrite(ms.ToArray());
}
释放Graphics对象g、image对象所占有的资源。
finally
{ ///释放占有的资源
g.Dispose();
image.Dispose();
}
}
}
}
ValidateCode类继承于System.Web.UI.Page类,因此,可以把ValidateCode类设置某一个Web窗体页的继承类。下述程序代码重写了System.Web.UI.Page类的OnLoad(EventArgs e)事件。重写之后的方法调用CreateValidateImage(string code)方法创建图文验证的图像,并在页面上输出该图像。
protected override void OnLoad(EventArgs e)
{
CreateValidateImage(length);
}
如果某一个页面的继承类设置为ValidateCode类,那么该页面首先将页面载入(Load)时调用CreateValidateImage(string code)方法创建图文验证的图像,并在页面上输出该图像。
另外,ValidateCode类还提供了一个公开方式的方法:CreateValidateImage(int length)。该方法可以根据指定长度(由length参数指定)来创建一个随机数字字符串,并创建图文验证的图像,以及在页面上输出该图像。
/// <summary>
/// 创建验证码的图片和验证码
/// </summary>
/// <param name="length">验证码的长度</param>
public void CreateValidateImage(int length)
{ ///创建验证码
code = CreateCode(length);
///创建验证码的图片
CreateValidateImage(code);
}
6.2.4 创建图文验证的页面
创建6.2.2和6.2.3小节中的ValidateCode类之后,要创建一个图文验证的页面是非常简单的事情。下面介绍创建图文验证的页面ValidateCode.aspx的具体步骤。
在某一个ASP.NET应用程序中添加Web窗体页ValidateCode.aspx,并删除该页面的代码隐藏文件。
删除ValidateCode.aspx页面的HTML代码,仅仅保留一行使用“@Page”指令的代码。
把该“@Page”指令的代码修改为如下形式的程序代码。同时,将该指令的Inherits属性的值设置为ValidateCode类,即ASPNETAJAXWeb.ValidateCode.Page.ValidateCode类。
<%@ Page Language="C#" AutoEventWireup="false"
Inherits="ASPNETAJAXWeb.ValidateCode.Page.ValidateCode" %>
注意:图文验证的页面ValidateCode.aspx无任何HTML代码和代码隐藏文件,它的Inherits属性的值为创建验证码的类ASPNETAJAXWeb.ValidateCode.Page. ValidateCode。
6.2.5 使用图文验证的页面
上述(6.2.1~6.2.4小节)创建的图文验证的ValidateCode.aspx页面可以在任何ASP.NET应用程序中使用。使用的具体方法如下:
把ValidateCode.aspx页面复制到要使用该页面的ASP.NET应用程序中。在图6.6中,AjaxUser应用程序把ValidateCode.aspx页面复制其根目录下。
使用引用的方式把程序集添加到使用该页面的ASP.NET应用程序中,在图6.7中,单击AjaxUser应用程序的【Bin】节点,选择【添加引用】命令来添加新的引用。

图6.6 复制ValidateCode.aspx页面 图6.7 添加引用操作
单击【添加引用】命令,弹出【添加引用】对话框,并选择要添加的程序集ASPNETAJAXWeb.ValidateCode.dll,如图6.8所示。
单击【确定】按钮,可以将程序集ASPNETAJAXWeb.ValidateCode.dll添加到AjaxUser应用程序中。此时,在【解决方案资源管理器】中查看AjaxUser应用程序,如图6.9所示。

图6.8 【添加引用】对话框 图6.9 查看添加引用后的程序集
在使用验证码的页面上添加一个Image控件,并将该控件的ImageUrl属性的值设置为ValidateCode.aspx页面。
<asp:Image ID="imgCode" runat="server" ImageUrl = "~/ValidateCode.aspx" />
检测用户输入的验证码是否正确。不妨设输入验证码的TextBox控件的ID属性的值为tbCode,那么可以使用下述程序代码检查用户输入的验证码是否正确,并在lbMessage控件中显示检测结果。
注意:ValidateCode.aspx页面产生的验证码保存在由关键字“VALIDATECODEKEY”标识的Session对象中。
///判断是否创建了验证码
if(Session[ValidateCode.VALIDATECODEKEY] == null) return;
///验证验证码是否相等
if(tbCode.Text != Session[ValidateCode.VALIDATECODEKEY].ToString())
{
lbMessage.Text = "验证码输入错误,请重新输入。";return;
}
6.3 智能化用户注册模块
用户注册功能由Register.aspx页面实现,它的代码隐藏文件为Register.aspx.cs。其中,该页面保存在AjaxUser应用程序的根目录下。Register.aspx页面为用户提供注册的功能。
6.3.1 数据库设计
AjaxUser应用程序使用的数据库的名称为AjaxUserDB,它只包含一个名称为User的表。该表保存用户信息,它包含的字段及其说明如表6.1所示。
表6.1 User表
|
字 段 名 |
数据类型 |
字段说明 |
键 引 用 |
备 注 |
|
ID |
int |
ID |
PK |
主键(自动增一) |
|
Username |
varchar(50) |
用户名称 |
|
|
|
Password |
varchar(255) |
用户密码 |
|
|
|
Status |
tinyint |
标识用户的状态 |
|
|
6.3.2 数据访问层设计
AjaxUser应用程序的数据访问层由UserDAL类实现,该类包含在ASPNETAJAXWeb. AjaxUser命名空间中。UserDAL类的代码定义在User.cs类文件中,并且还引入了System.Data.SqlClient命名空间。下面的程序代码声明了UserDAL类,并声明了1个只读变量ConnectionString,该变量从Web.config配置文件中获取访问数据库的连接字符串。其中,UserDAL类中的方法代码已经省略。
using System.Data.SqlClient;
namespace ASPNETAJAXWeb.AjaxUser
{
/// <summary>
/// 操作用户信息的数据访问层
/// </summary>
public class UserDAL
{
/// <summary>
/// 保存数据库的连接字符串
/// </summary>
private readonly string ConnectionString
= ConfigurationManager.ConnectionStrings[
"SQLCONNECTIONSTRING"].ConnectionString;
public UserDAL(){}
……
}
}
在智能化用户注册模块中,它的数据访问层只实现了两个功能:检测用户名称是否被使用和提交用户的注册信息到数据库中。这两个功能分别由CheckUser(string username)和AddUser(String username,String password)方法实现。
CheckUser(string username)方法检测用户即将注册的用户名称(由username参数指定)在数据库中是否存在,即是否被别人注册。声明该方法的程序代码如下:
public SqlDataReader CheckUser(string username)
CheckUser(string username)方法返回类型为SqlDataReader,它使用Pr_CheckUser存储过程从数据库的User表中检测用户名称已经存在记录的数量。该存储过程的程序代码如下:
CREATE PROCEDURE Pr_CheckUser
(
@Username varchar(50)
)
AS
SELECT COUNT(*) AS UserCount
FROM [User]
WHERE Username = @Username
在下述程序代码中,CheckUser(string username)方法检测username参数指定的名称是否在数据库的User表中存在。该方法的具体实现步骤如下:
使用连接字符串ConnectionString创建SqlConnection对象con,该对象用来连接数据库。
设置执行的存储过程为Pr_CheckUser,并设置myCommand对象的执行方式为存储过程。
添加存储过程需要的@Username参数,并进行赋值。
执行存储过程Pr_CheckUser,并将结果保存到SqlDataReader对象dr中。
如果上述操作成功,则返回SqlDataReader对象dr。
public SqlDataReader CheckUser(string username)
{ ///定义数据库的Connection 和 Command
SqlConnection myConnection = new SqlConnection(ConnectionString);
SqlCommand myCommand = new SqlCommand("Pr_CheckUser",myConnection);
///定义访问数据库的方式为存储过程
myCommand.CommandType = CommandType.StoredProcedure;
///创建访问数据库的参数
SqlParameter parameterUserName
= new SqlParameter("@Username",SqlDbType.VarChar,50);
parameterUserName.Value = username;
myCommand.Parameters.Add(parameterUserName);
SqlDataReader dr = null;
try
{ ///打开数据库的连接
myConnection.Open();
}
catch(Exception ex){throw new Exception("数据库连接失败!",ex);}
try
{ ///执行数据库的存储过程(访问数据库)
dr = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
}
catch(Exception ex){throw new Exception(ex.Message,ex);}
return dr; ///返回dr
}
AddUser(String username,String password)方法将用户的注册信息(其中,用户名称由username参数指定,用户密码由password参数指定)插入到数据库的User表中。声明该方法的程序代码如下:
public int AddUser(String username,String password)
AddUser(String username,String password)方法返回类型为int,它将返回新用户在User表中的ID值。该方法使用Pr_AddUser存储过程将用户的注册信息插入到数据库的User表中。该存储过程的程序代码如下:
CREATE PROCEDURE Pr_AddUser
(
@Username varchar(50),
@Password varchar(255)
)
AS
INSERT INTO [User]
(Username,Password,Status)
VALUES
(@Username,@Password,1)
RETURN @@Identity
在下述程序代码中,AddUser(String username,String password)方法将用户的注册信息插入到数据库的User表中。该方法的具体实现步骤如下:
使用连接字符串ConnectionString创建SqlConnection对象con,该对象用来连接数据库。
设置执行的存储过程为Pr_AddUser,并设置myCommand对象的执行方式为存储过程。
添加存储过程需要的@Username、@Password和@UserID参数。其中,前两个参数为输入类型的参数,后面一个参数为返回类型的参数,它将保存新插入记录的ID值。
执行存储过程Pr_AddUser。
如果上述操作成功,则返回@UserID参数的值。
public int AddUser(String username,String password)
{ ///定义数据库的Connection 和 Command
SqlConnection myConnection = new SqlConnection(ConnectionString);
SqlCommand myCommand = new SqlCommand("Pr_AddUser",myConnection);
///定义访问数据库的方式为存储过程
myCommand.CommandType = CommandType.StoredProcedure;
///创建访问数据库的参数
SqlParameter parameterUserName
= new SqlParameter("@UserName",SqlDbType.VarChar,32);
parameterUserName.Value = username;
myCommand.Parameters.Add(parameterUserName);
SqlParameter parameterPassword
= new SqlParameter("@Password",SqlDbType.VarChar,100);
parameterPassword.Value = password;
myCommand.Parameters.Add(parameterPassword);
SqlParameter parameterUserID
= new SqlParameter("@UserID",SqlDbType.Int,4);
parameterUserID.Direction = ParameterDirection.ReturnValue;
myCommand.Parameters.Add(parameterUserID);
try
{ ///打开数据库的连接
myConnection.Open();
}
catch(Exception ex){throw new Exception("数据库连接失败!",ex);}
try
{ ///执行数据库的存储过程(访问数据库)
myCommand.ExecuteNonQuery();
}
catch(Exception ex){throw new Exception(ex.Message,ex);}
finally
{
if(myConnection.State == ConnectionState.Open)
{ ///关闭数据库的连接
myConnection.Close();
}
}
return (int)parameterUserID.Value;
}
6.3.3 用户注册页面设计
用户注册功能由Register.aspx页面实现。该页面为用户提供了输入用户名称、用户密码、确认密码、验证码、提交用户注册信息等功能。Register.aspx页面添加了4个TextBox控件和2个Button控件。
下述程序代码声明了1个TextBox控件,用来输入用户名称,ID属性的值为tbUsername。该控件使用了1个TextBoxWatermarkExtender控件和3个ValidatorCalloutExtender控件,它们的ID属性的值分别为wmeName、vceNameBlank、vceNameValue和vceRevName。其中,wmeName控件为tbUsername控件显示水印值“请输入用户名称”;vceNameBlank、vceNameValue和vceRevName控件分别以提示样式显示验证结果。
另外,tbUsername控件使用2个RequiredFieldValidator控件和1个RegularExpressionValidator控件,它们的ID属性的值分别为rfNameBlank、rfNameValue和revName。其中,rfNameBlank控件验证tbName控件的内容不能为空,即用户输入的名称不能为空;rfNameValue控件验证tbName控件的内容不能等于“请输入用户名称”(wmeName水印控件的水印值),这样可以防止用户不输入任何名称就注册;revName控件验证tbUsername控件内容的最小长度为1、最大长度为50。
<!-- 以下HTML代码用来实现输入用户名称的功能 -->
用户名称:<asp:TextBox ID="tbUsername" runat="server" SkinID="tbSkin"
Width="60%" MaxLength="50"></asp:TextBox>
<asp:RequiredFieldValidator ID="rfNameBlank" runat="server"
ControlToValidate="tbUsername" Display="none"
ErrorMessage="用户名称不能为空!"></asp:RequiredFieldValidator>
<asp:RequiredFieldValidator ID="rfNameValue" runat="server"
ControlToValidate="tbUsername" Display="none"
InitialValue="请输入用户名称"
ErrorMessage="用户名称不能为空!"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="revName" runat="server"
ControlToValidate="tbUsername" Display="none"
ErrorMessage="用户名称的长度最大为50,请重新输入。"
ValidationExpression=".{1,50}">
</asp:RegularExpressionValidator>
<ajaxToolkit:TextBoxWatermarkExtender ID="wmeName" runat="server"
TargetControlID="tbUsername" WatermarkText="请输入用户名称"
WatermarkCssClass="Watermark">
</ajaxToolkit:TextBoxWatermarkExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vceNameBlank"
runat="server" TargetControlID="rfNameBlank"
HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vceNameValue"
runat="server" TargetControlID="rfNameValue"
HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vceNameRegex"
runat="server" TargetControlID="revName"
HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
在下述程序代码中,btnCheck控件检测用户输入的名称是否存在,并在lbCheckResult控件中显示检测的结果。
<asp:Button ID="btnCheck" runat="server" Text="检查是否重名"
CausesValidation="False" OnClick="btnCheck_Click"
SkinID="btnSkin" />
<asp:Label ID="lbCheckResult" runat="server"
ForeColor="Red"></asp:Label>
在下述程序代码中,btnRegister控件将用户的注册信息提交到数据库的User表中,并在lbMessage控件中显示注册的结果。
<asp:Button ID="btnRegister" runat="server" Text="注册"
OnClick="btnRegister_Click" Width="80px" SkinID="btnSkin" />
<asp:Label ID="lbMessage" runat="server" CssClass="Text"
ForeColor="Red"></asp:Label>
综上所述,Register.aspx页面的设计界面如图6.10所示。
Register.aspx页面的完整HTML设计代码(不包括简单的HTML元素,如<table>、<tr>等)如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Register.aspx.cs"
Inherits="Register" StylesheetTheme="ASPNETAjaxWeb" %>
<head runat="server"><title>用户注册</title></head>
<body><form id="form1" runat="server">

图6.10 用户注册页面Register.aspx的设计界面
<asp:ScriptManager ID="sm" runat="server" />
<asp:UpdatePanel ID="up" runat="server"><ContentTemplate>
<!-- 以下HTML代码用来实现输入用户名称的功能 -->
用户名称:<asp:TextBox ID="tbUsername" runat="server" SkinID="tbSkin"
Width="60%" MaxLength="50"></asp:TextBox>
<asp:Button ID="btnCheck" runat="server" Text="检查是否重名"
CausesValidation="False" OnClick="btnCheck_Click"
SkinID="btnSkin" />
<asp:Label ID="lbCheckResult" runat="server"
ForeColor="Red"></asp:Label>
<asp:RequiredFieldValidator ID="rfNameBlank" runat="server"
ControlToValidate="tbUsername" Display="none"
ErrorMessage="用户名称不能为空!"></asp:RequiredFieldValidator>
<asp:RequiredFieldValidator ID="rfNameValue" runat="server"
ControlToValidate="tbUsername" Display="none"
InitialValue="请输入用户名称"
ErrorMessage="用户名称不能为空!"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="revName" runat="server"
ControlToValidate="tbUsername" Display="none"
ErrorMessage="用户名称的长度最大为50,请重新输入。"
ValidationExpression=".{1,50}">
</asp:RegularExpressionValidator>
<ajaxToolkit:TextBoxWatermarkExtender ID="wmeName" runat="server"
TargetControlID="tbUsername" WatermarkText="请输入用户名称"
WatermarkCssClass="Watermark">
</ajaxToolkit:TextBoxWatermarkExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vceNameBlank"
runat="server" TargetControlID="rfNameBlank"
HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vceNameValue"
runat="server" TargetControlID="rfNameValue"
HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vceNameRegex"
runat="server" TargetControlID="revName"
HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<!-- 以下HTML代码用来实现输入用户密码的功能 -->
用户密码:<asp:TextBox ID="tbPassword" runat="server" SkinID="tbSkin"
Width="60%" MaxLength="50" TextMode="Password">
</asp:TextBox><br />
<asp:Label ID="lbHelp" runat="server"></asp:Label>
<asp:RequiredFieldValidator ID="rfPwdBlank" runat="server"
ControlToValidate="tbPassword" Display="none"
ErrorMessage="用户密码不能为空!"></asp:RequiredFieldValidator>
<ajaxToolkit:ValidatorCalloutExtender ID="vcePwdBlank"
runat="server" TargetControlID="rfPwdBlank"
HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<ajaxToolkit:PasswordStrength ID="psPassword" runat="server"
TargetControlID="tbPassword" DisplayPosition="RightSide"
TextCssClass="PasswordStrengthText"
HelpHandlePosition="BelowLeft" HelpStatusLabelID="lbHelp"
MinimumNumericCharacters="2" MinimumSymbolCharacters="2"
PreferredPasswordLength="10"
RequiresUpperAndLowerCaseCharacters="true"
StrengthIndicatorType="Text"
TextStrengthDescriptions="很差;差;一般;好;很好"
CalculationWeightings="40;20;20;20">
</ajaxToolkit:PasswordStrength>
<!-- 以下HTML代码用来实现输入确认密码的功能 -->
确认密码:<asp:TextBox ID="tbPasswordStr" runat="server"
SkinID="tbSkin" Width="60%" MaxLength="50"
TextMode="Password"></asp:TextBox>
<asp:CompareValidator ID="cvPwd" runat="server"
ControlToValidate="tbPassword"
ControlToCompare="tbPasswordStr" Display="none"
Operator="Equal" ErrorMessage="两次输入的密码不相同,请重新输入。">
</asp:CompareValidator>
<ajaxToolkit:ValidatorCalloutExtender ID="vcePassword"
runat="server" TargetControlID="cvPwd"
HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<!-- 以下HTML代码用来实现输入验证码的功能 -->
验 证 码:<asp:TextBox ID="tbCode" runat="server" SkinID="tbSkin"
Width="80px"></asp:TextBox>
<asp:Image ID="imgCode" runat="server"
ImageUrl = "~/ValidateCode.aspx" />
<!-- 以下HTML代码用来实现提交用户信息的功能 -->
<asp:Button ID="btnRegister" runat="server" Text="注册"
OnClick="btnRegister_Click" Width="80px" SkinID="btnSkin" />
<asp:Label ID="lbMessage" runat="server" CssClass="Text"
ForeColor="Red"></asp:Label>
</ContentTemplate></asp:UpdatePanel>
</form></body>
6.3.4 密码强度提示
在下述程序代码中,tbPassword控件使用PasswordStrength控件提示用户输入密码的强度,包括5个等级:“很差”、“差”、“一般”、“好”和“很好”。其中,“很好”等级密码的最小长度为10,至少包含2个数字,至少包含2个特殊字符,区分英文字母的大小写形式。
<!-- 以下HTML代码用来实现输入用户密码的功能 -->
用户密码:<asp:TextBox ID="tbPassword" runat="server" SkinID="tbSkin"
Width="60%" MaxLength="50" TextMode="Password">
</asp:TextBox><br />
<asp:Label ID="lbHelp" runat="server"></asp:Label>
<asp:RequiredFieldValidator ID="rfPwdBlank" runat="server"
ControlToValidate="tbPassword" Display="none"
ErrorMessage="用户密码不能为空!"></asp:RequiredFieldValidator>
<ajaxToolkit:ValidatorCalloutExtender ID="vcePwdBlank"
runat="server" TargetControlID="rfPwdBlank"
HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<ajaxToolkit:PasswordStrength ID="psPassword" runat="server"
TargetControlID="tbPassword" DisplayPosition="RightSide"
TextCssClass="PasswordStrengthText"
HelpHandlePosition="BelowLeft" HelpStatusLabelID="lbHelp"
MinimumNumericCharacters="2" MinimumSymbolCharacters="2"
PreferredPasswordLength="10"
RequiresUpperAndLowerCaseCharacters="true"
StrengthIndicatorType="Text"
TextStrengthDescriptions="很差;差;一般;好;很好"
CalculationWeightings="40;20;20;20">
</ajaxToolkit:PasswordStrength>
Register.aspx页面运行之后,如果用户在【用户密码】输入框中输入密码,则页面将动态显示该密码的强度和提示信息,如图6.11所示。

图6.11 密码强度提示
6.3.5 检测用户名称是否已注册
用户单击Register.aspx页面上的【检查是否重名】按钮,可以检测用户名称是否已经注册。该功能由Register.aspx页面的btnCheck控件的btnCheck_Click(object sender,EventArgs e)事件实现。
btnCheck_Click(object sender,EventArgs e)事件定义在代码隐藏文件Register.aspx.cs中。该文件引入了两个新的命名空间:ASPNETAJAXWeb.ValidateCode.Page和ASPNETAJAXWeb. AjaxUser。程序代码如下:
///引入新的命名空间
using ASPNETAJAXWeb.ValidateCode.Page;
using ASPNETAJAXWeb.AjaxUser;
在下述程序代码中,btnCheck_Click(object sender,EventArgs e)事件可以检测用户名称是否已经注册。该事件首先检测用户输入的名称是否为空,如果为空,则提示用户输入名称;如果不为空,将调用UserDAL类的CheckUser(string username)方法从数据库中检测用户输入的名称是否存在,并返回SqlDataReader对象dr。然后根据dr判断该名称是否存在,并在lbCheckResult控件上显示相应的检测结果。
protected void btnCheck_Click(object sender,EventArgs e)
{ ///检查用户名称是否为空
if(string.IsNullOrEmpty(tbUsername.Text) == true)
{
lbCheckResult.Text = "很遗憾,您输入的用户名称为空,不能注册。请重新输入";
lbCheckResult.ForeColor = System.Drawing.Color.Red;
return;
}
///检查用户名称是否存在
UserDAL user = new UserDAL();
SqlDataReader dr = user.CheckUser(tbUsername.Text);
if(dr == null)
{ ///如果不存在,则可以使用
lbCheckResult.Text = "恭喜您,您选择的用户名称可以使用。";
lbCheckResult.ForeColor = System.Drawing.Color.Green;
return;
}
if(dr.Read())
{ ///如果存在,则不能注册
if(Int32.Parse(dr["UserCount"].ToString()) > 0)
{
lbCheckResult.Text
= "很遗憾,您选择的用户名称已经被使用了。请重新选择";
lbCheckResult.ForeColor = System.Drawing.Color.Red;
}
else
{ ///如果不存在,则可以使用
lbCheckResult.Text = "恭喜您,您选择的用户名称可以使用。";
lbCheckResult.ForeColor = System.Drawing.Color.Green;
}
}
else
{ ///如果不存在,则可以使用
lbCheckResult.Text = "恭喜您,您选择的用户名称可以使用。";
lbCheckResult.ForeColor = System.Drawing.Color.Green;
}
dr.Close();
}
6.3.6 用户注册
用户单击Register.aspx页面上的【注册】按钮将触发btnRegister_Click(object sender, EventArgs e)事件,该事件实现用户注册功能。
在下述程序代码中,btnRegister_Click(object sender,EventArgs e)事件将用户的注册信息插入到数据库的User表中。该事件首先检测用户输入的验证码是否正确,如果不正确,则显示提示验证码错误,并中止事件;如果验证码正确,则调用UserDAL类的AddUser(String username,String password)方法将用户的注册信息插入到数据库的User表中,并返回新插入记录的ID值。最终,在lbMessage控件上显示注册的结果。
protected void btnRegister_Click(object sender,EventArgs e)
{ ///判断是否创建了验证码
if(Session[ValidateCode.VALIDATECODEKEY] == null) return;
///验证验证码是否相等
if(tbCode.Text != Session[ValidateCode.VALIDATECODEKEY].ToString())
{
lbMessage.Text = "验证码输入错误,请重新输入。";
return;
}
///注册新用户
UserDAL user = new UserDAL();
if(user.AddUser(tbUsername.Text,tbPassword.Text) > 0)
{
lbMessage.Text = "恭喜您,注册成功!";
}
else{lbMessage.Text = "很遗憾,注册失败!";}
}
将Register.aspx页面设置为AjaxUser应用程序的起始页面,并运行该程序,Register.aspx页面的起始界面如图6.12所示。

图6.12 用户注册页面Register.aspx的起始界面
6.4 用户登录和注销
用户登录和注销功能分别由Login.aspx和Logoff.aspx页面实现,它们的代码隐藏文件分别为Login.aspx.cs和Logoff.aspx.cs。其中,这两个页面都保存在AjaxUser应用程序的根目录下。
6.4.1 数据访问层设计
在用户登录和注销中,它的数据访问层只实现了1个功能:检测用户名称和用户密码是否正确,如果正确,则能够登录,否则不能够登录。该功能由GetUserLogin(string username,string password)方法实现。
GetUserLogin(string username,string password)方法根据用户输入的名称和密码(分别由username和password参数指定)从数据库的User表中检测该记录的ID,如果不存在,则返回空值。声明该方法的程序代码如下:
public SqlDataReader GetUserLogin(string username,string password)
GetUserLogin(string username,string password)方法返回类型为SqlDataReader。它使用Pr_GetUserLogin存储过程根据用户输入的名称和密码从数据库的User表中检测该记录的ID。该存储过程的程序代码如下:
CREATE PROCEDURE Pr_GetUserLogin
(
@Username varchar(50),
@Password varchar(255)
)
AS
SELECT ID
FROM [User]
WHERE Username = @Username AND Password = @Password
在下述程序代码中,GetUserLogin(string username,string password)方法根据用户输入的名称和密码从数据库的User表中检测该记录的ID。该方法的具体实现步骤如下:
使用连接字符串ConnectionString创建SqlConnection对象con,该对象用来连接数据库。
设置执行的存储过程为Pr_GetUserLogin,并设置myCommand对象的执行方式为存储过程。
添加存储过程需要的@Username和@Password参数,并进行赋值。
执行存储过程Pr_GetUserLogin,并将结果保存到SqlDataReader对象dr中。
如果上述操作成功,则返回SqlDataReader对象dr。
public SqlDataReader GetUserLogin(string username,string password)
{ ///定义数据库的Connection 和 Command
SqlConnection myConnection = new SqlConnection(ConnectionString);
SqlCommand myCommand = new SqlCommand("Pr_GetUserLogin",myConnection);
///定义访问数据库的方式为存储过程
myCommand.CommandType = CommandType.StoredProcedure;
///创建访问数据库的参数
SqlParameter parameterUserName
= new SqlParameter("@Username",SqlDbType.VarChar,50);
parameterUserName.Value = username;
myCommand.Parameters.Add(parameterUserName);
SqlParameter parameterPassword
= new SqlParameter("@Password",SqlDbType.VarChar,255);
parameterPassword.Value = password;
myCommand.Parameters.Add(parameterPassword);
SqlDataReader dr = null;
try
{ ///打开数据库的连接
myConnection.Open();
}
catch(Exception ex){throw new Exception("数据库连接失败!",ex);}
try
{ ///执行数据库的存储过程(访问数据库)
dr = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
}
catch(Exception ex){throw new Exception(ex.Message,ex);}
return dr; ///返回dr
}
6.4.2 避免登录时的SQL注入
Pr_GetUserLogin存储过程能够避免用户登录时的SQL注入,这是因为该存储过程使用参数来传入用户的名称和密码。这样,用户输入的名称和密码都被看成一个整体,即当成一个完整的值来处理,而不是把它们的值作为SQL语句的一部分。Pr_GetUserLogin存储过程的完整代码如下:
CREATE PROCEDURE Pr_GetUserLogin
(
@Username varchar(50),
@Password varchar(255)
)
AS
SELECT ID
FROM [User]
WHERE Username = @Username AND Password = @Password
如果用户输入的名称和密码分别为“username OR 'a'='a”和“password”,那么在该存储过程中,上述的WHERE语句被解释为如下语句:
WHERE Username = [username OR 'a'='a] AND Password = 'Password'
在上述语句中,Username = [username OR 'a'='a]构成一个完整的赋值表达式。若使用以下SQL语句来获取登录信息(即用户的ID):
SELECT ID FROM [User] WHERE Username = 名称 AND Password = 密码
当用户输入的名称和密码分别为“username OR 'a'='a”和“password”时,上述SQL语句被解释为如下语句:
SELECT ID FROM [User] WHERE Username = 'username OR 'a'='a' AND Password = 'Password'
因为上述SQL语句中存在永真的条件“'a'='a'”,从而导致WHERE子句为真。因此,上述SQL语句实际上不需要任何用户名称和密码就能够登录系统。
6.4.3 设计用户登录界面
用户登录功能由Login.aspx页面实现。该页面为用户提供了输入名称、密码等功能,同时,它还将用户输入的名称和密码提交到数据库,并判断该名称和密码是否正确。Login.aspx页面添加了3个TextBox控件和1个Button控件。
下述程序代码声明了1个TextBox控件,用来输入用户名称,ID属性的值为tbUsername。该控件使用了1个TextBoxWatermarkExtender控件和3个ValidatorCalloutExtender控件,它们的ID属性的值分别为wmeName、vceNameBlank、vceNameValue和vceNameRegex。其中,wmeName控件为tbUsername控件显示水印值“请输入用户名称”;vceNameBlank、vceNameValue和vceNameRegex控件分别以提示样式显示验证结果。
另外,tbUsername控件使用2个RequiredFieldValidator控件和1个RegularExpressionValidator控件,它们的ID属性的值分别为rfNameBlank、rfNameValue和revName。其中,rfNameBlank控件验证tbUsername控件的内容不能为空,即用户输入的名称不能为空;rfNameValue控件验证tbUsername控件的内容不能等于“请输入用户名称”(wmeName水印控件的水印值),这样可以防止用户不输入任何内容就登录;revName控件验证tbUsername控件内容的最小长度为1、最大长度为50。
<!-- 以下HTML代码用来实现输入用户名称的功能 -->
用户名称:<asp:TextBox ID="tbUsername" runat="server" SkinID="tbSkin"
Width="60%" MaxLength="50"></asp:TextBox>
<asp:RequiredFieldValidator ID="rfNameBlank" runat="server"
ControlToValidate="tbUsername" Display="none"
ErrorMessage="用户名称不能为空!"></asp:RequiredFieldValidator>
<asp:RequiredFieldValidator ID="rfNameValue" runat="server"
ControlToValidate="tbUsername" Display="none"
InitialValue="请输入用户名称" ErrorMessage="用户名称不能为空!">
</asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="revName" runat="server"
ControlToValidate="tbUsername" Display="none"
ErrorMessage="用户名称的长度最大为50,请重新输入。"
ValidationExpression=".{1,50}"></asp:RegularExpressionValidator>
<ajaxToolkit:TextBoxWatermarkExtender ID="wmeName" runat="server"
TargetControlID="tbUsername" WatermarkText="请输入用户名称"
WatermarkCssClass="Watermark">
</ajaxToolkit:TextBoxWatermarkExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vceNameBlank" runat="server"
TargetControlID="rfNameBlank" HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vceNameValue" runat="server"
TargetControlID="rfNameValue" HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vceNameRegex" runat="server"
TargetControlID="revName" HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
综上所述,Login.aspx页面的设计界面如图6.13所示。

图6.13 用户登录页面Login.aspx的设计界面
Login. aspx页面的完整HTML设计代码(不包括简单的HTML元素,如<table>、<tr>等)如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs"
Inherits="Login" StylesheetTheme="ASPNETAjaxWeb" %>
<head runat="server"><title>用户登录</title></head>
<body><form id="form1" runat="server">
<asp:ScriptManager ID="sm" runat="server" />
<!-- 以下HTML代码用来实现输入用户名称的功能 -->
用户名称:<asp:TextBox ID="tbUsername" runat="server" SkinID="tbSkin"
Width="60%" MaxLength="50"></asp:TextBox>
<asp:RequiredFieldValidator ID="rfNameBlank" runat="server"
ControlToValidate="tbUsername" Display="none"
ErrorMessage="用户名称不能为空!"></asp:RequiredFieldValidator>
<asp:RequiredFieldValidator ID="rfNameValue" runat="server"
ControlToValidate="tbUsername" Display="none"
InitialValue="请输入用户名称" ErrorMessage="用户名称不能为空!">
</asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="revName" runat="server"
ControlToValidate="tbUsername" Display="none"
ErrorMessage="用户名称的长度最大为50,请重新输入。"
ValidationExpression=".{1,50}"></asp:RegularExpressionValidator>
<ajaxToolkit:TextBoxWatermarkExtender ID="wmeName" runat="server"
TargetControlID="tbUsername" WatermarkText="请输入用户名称"
WatermarkCssClass="Watermark">
</ajaxToolkit:TextBoxWatermarkExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vceNameBlank" runat="server"
TargetControlID="rfNameBlank" HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vceNameValue" runat="server"
TargetControlID="rfNameValue" HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vceNameRegex" runat="server"
TargetControlID="revName" HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<!-- 以下HTML代码用来实现输入用户密码的功能 -->
用户密码:<asp:TextBox ID="tbPassword" runat="server" SkinID="tbSkin"
Width="60%" MaxLength="50"></asp:TextBox>
<asp:RequiredFieldValidator ID="rfPwdBlank" runat="server"
ControlToValidate="tbPassword" Display="none"
ErrorMessage="用户密码不能为空!"></asp:RequiredFieldValidator>
<asp:RequiredFieldValidator ID="rfPwdValue" runat="server"
ControlToValidate="tbPassword" Display="none"
InitialValue="请输入用户密码" ErrorMessage="用户密码不能为空!">
</asp:RequiredFieldValidator>
<ajaxToolkit:TextBoxWatermarkExtender ID="twePwd" runat="server"
TargetControlID="tbPassword" WatermarkText="请输入用户密码"
WatermarkCssClass="Watermark">
</ajaxToolkit:TextBoxWatermarkExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vcePwdBlank" runat="server"
TargetControlID="rfPwdBlank" HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<ajaxToolkit:ValidatorCalloutExtender ID="vcePwdValue" runat="server"
TargetControlID="rfPwdValue" HighlightCssClass="Validator">
</ajaxToolkit:ValidatorCalloutExtender>
<!-- 以下HTML代码用来实现输入验证码的功能 -->
验 证 码:<asp:TextBox ID="tbCode" runat="server" SkinID="tbSkin"
Width="80px"></asp:TextBox>
<asp:Image ID="imgCode" runat="server" ImageUrl = "~/ValidateCode.aspx" />
<asp:Label ID="lbMessage" runat="server" CssClass="Text"
ForeColor="Red"></asp:Label>
<asp:Button ID="btnLogin" runat="server" Text="登录"
OnClick="btnLogin_Click" Width="80px" />
</form></body>
6.4.4 用户登录
单击Login.aspx页面上的【登录】按钮将触发btnLogin_Click(object sender,EventArgs e)事件,该事件实现用户登录功能。
在下述程序代码中,btnLogin_Click(object sender,EventArgs e)事件将根据用户输入的名称和密码获取该记录的ID值。该事件首先检测用户输入的验证码是否正确,如果不正确,则显示提示验证码错误,并中止事件;如果验证码正确,则调用UserDAL类的GetUserLogin(string username,string password)方法根据用户输入的名称和密码获取该记录的ID值,并返回获取的ID值。最后,在网页上显示用户登录的结果。
protected void btnLogin_Click(object sender,EventArgs e)
{ ///判断是否创建了验证码
if(Session[ValidateCode.VALIDATECODEKEY] == null) return;
///验证验证码是否相等
if(tbCode.Text != Session[ValidateCode.VALIDATECODEKEY].ToString())
{
lbMessage.Text = "验证码输入错误,请重新输入。";
return;
}
///判断用户的名称和密码是否正确
UserDAL user = new UserDAL();
SqlDataReader dr = user.GetUserLogin(tbUsername.Text,tbPassword.Text);
if(dr == null) return;
if(dr.Read())
{ ///用户登录成功
Session["UserInfo"] = dr["ID"].ToString();
Response.Write("用户登录成功!");
}
else
{ ///用户登录失败
Response.Write("用户登录失败!");
}
dr.Close();
Response.End(); ///中止网页输出
}
将Login.aspx页面设置为AjaxUser应用程序的起始页面,并运行该程序,Login.aspx页面的初始界面如图6.14所示。

图6.14 用户登录页面Login.aspx的起始页面
6.4.5 用户注销
用户注销功能由Logoff.aspx页面实现,它的代码隐藏文件为Logoff.aspx.cs。该页面在其代码隐藏文件的Page_Load(object sender,EventArgs e)事件中实现用户注销功能。
在下述程序代码中,Page_Load(object sender,EventArgs e)事件首先判断保存在Session对象中的用户信息(由关键字“UserInfo”标识)是否为空。如果不为空,则清空该内容,并停止当前Session,最后重定向到登录页面Default.aspx。
protected void Page_Load(object sender, EventArgs e)
{
if(Session["UserInfo"] != null)
{ ///清空用户登录信息
Session["UserInfo"] = null;
Session.Clear();
Session.Abandon(); ///取消当前Session
}
Response.Redirect("~/Default.aspx"); ///重定向到登录页面
}





