Rocho.J

人脑是不可靠的, 随时记录感悟并且经常重复!

 

学习笔记---验证控件

作为程序员, 永远别指望用户按照规则进行输入, 比较理想的状况是在客户端浏览器和服务器端进行双重验证. 通常在客户端浏览器进行非功能性的常规验证, 如: 非空验证、范围验证及输入格式验证等, 而在服务器端进行功能性验证, 如: 检查账户是否存在, 检查用户权限等. 客户端浏览器的验证一般通过JavaScript实现, 验证过程与服务器无关, 在客户端浏览器验证通过后, 才将请求参数发送到服务器, 由服务端再次进行验证.微软的ASP.NET验证框架实现了客户端浏览器和服务器的双重验证.

 

1. IValidator接口: ---ErrorMessage属性、IsValid属性、Validate()方法
验证控件的核心是IValidator接口(System.Web.UI下), 其中有三个重要的成员: ErrorMessage属性、IsValid属性及Validate()方法, 执行validate方法后, 将设置IsValid属性.

 

2. BaseValidator抽象类:
为方便使用, ASP.NET通过实现了IValidator接口的抽象类BaseValidator为我们提供了大量的属性和方法.其中比较重要的属性有:
ErrorMessage: 设置错误信息.
IsValid: 验证结果.
ControlToValidate: 对那个控件进行验证(通过ID查找)
Display: 错误信息的显示方式, 有static、dynamic、none三中, static提前占位, 而dynamic不提前占位; none表示不在验证控件中显示, 通常配合BaseValiddator的Text属性, 将错误信息显示在ValidationSummary中.
Text: 如果设置了Text, 验证控件将只显示Text内容, 而ErrorMessage的信息将放到ValidationSummary中显示.
ValidationGrop: 只验证同一组的页面对象, 建议一开始就设置好分组.
EnableClientScript: 是否启用客户端验证
SetFocusOnError: 自动将焦点移到未通过验证的空间内.

 

3. ASP.NET验证控件:
RequiredFieldValidator: 检查用户是否输入, 除此控件外, 其他控件无输入时将默认不检查, 直接通过.
RegularExpressionValidator: 使用正则表达式进行输入内容的验证.
    正则表达式内容:
    元数据: a
    [a,b,c]: abc任选一个, 如果可选项很多, 可用[a-z]
    \w: 大写字母、小写字母、0-9;   \W: 非大写字母、小写字母和0-9之外的字符;   \w\W: 所有字符
    \d: 0-9;   \D: 非0-9的字符
    \s: 空白
    数量词: ?表示0-1个;   +表示1-n个;   *表示0-n个;  {m,n}表示最少m个, 最多n个
    (): 分组
CompareValidator: 用来比较两个绑定控件的内容. 需要通过Operator指定比较方式, 还需要通过Type指定比较的数据类型.
RangeValidator: 判断内容是否在指定范围, 通过MaximumValue和MinimumValue指定最大和最小值, 也需要通过Type指定数据类型.
CustomValidator: 自定义验证, 既可以在客户端浏览器验证也可以在服务器验证.客户端验证需要通过ClientValidationFunction属性设置验证用的JavaScript脚本函数名, 服务器端验证需要通过控件的ServerValidate事件来完成.
    .aspx文件中, 客户端浏览器验证的JavaScript脚本函数的形式如下:
    function ClientValidate(source,clientside_arguments)
    {

    }
    .cs文件中, 服务器端验证时ServerValidate事件的处理方法, 验证结果需要通过参数args.IsValid属性向验证框架返回结果, args.IsValid默认true;
    protected void ServerValidate(object source, ServerValidateEventArgs args)
    {

    }
ValidationSummary: 收集页面上的验证信息并统一显示, 还可以通过ValidationGroup属性显示一组验证信息.
注意: 按钮上有一个默认开启的属性CausesValidation, 表示该按钮是否激发验证, 如果该按钮通被包含在同一个ValidationGroup中, 则只进行该组中控件的验证.

 

4. 服务器端验证的时机:
页面对象有11个事件, 有两个非常重要的时间点(博客里有那张图): 一个是在Page_InitComplete --- Page_PreLoad之间, 完成控件的视图状态的读取以及请求参数到控件属性的赋值操作; 第二个是在Page_Load --- Page_LoadComplete之间, 完成服务器端请求参数处理和控件事件登记、通过页面对象的Validate()方法验证控件, 并通过其IsValid属性获得结果、控件事件的执行.
服务器端验证时通过ServerValidate事件来完成的, 所以验证时机是在Page_Load事件之后, 控件事件之前执行. 页面上会有一个验证控件集合Page.Validators, 当执行服务器验证时, 遍历该集合, 改变页面对象的IsValid属性. 如果我们希望提前验证, 需要手动调用this.Validate()方法.

 

//default.aspx代码

代码
<%@ 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>
<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>

 

//default.aspx.cs代码

代码
using System;
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;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
this.validator_range_birth.MaximumValue = DateTime.Now.ToShortDateString();
this.validator_range_birth.MinimumValue = DateTime.Now.AddYears(-150).ToShortDateString();
}

protected void Page_Load(object sender, EventArgs e)
{
if (this.IsPostBack)
{
//this.Validate(); //手动调用验证方法
}

}
protected void 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; //这里使用验证控件上的IsValid属性
}
}
}
protected void Validator_Dcode_ServerValidate(object source, ServerValidateEventArgs args)
{
//每次复位Validator状态
args.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)
// {
// args.IsValid = true; //这里必须用args.IsValid, 不能用this.validator_dcode.isvalid = true, 因为最后args.IsValid会覆盖掉this.validator_dcode.IsValid, 分析在最后
// }
//}
//else
//{
// args.IsValid = false;
//}
#endregion

#region Session
if (this.Session["Dycode"] != null)
{
string num = this.Session["Dycode"] as string;
if (num == this.txt_dcode.Text)
{
args.IsValid
= true;
}
else
{
args.IsValid
= false;
}
}

#endregion
}
}

 

 

//DynamicCode.ashx代码

代码
<%@ WebHandler Language="C#" Class="DynamicCode" %>

using System;
using System.Web;

//使用Session记得在ashx中, 添加IRequiresSessionState的接口, 而aspx文件默认就是支持的
public class DynamicCode : IHttpHandler,System.Web.SessionState.IRequiresSessionState {

public void 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);
}

public bool IsReusable {
get {
return false;
}
}

}

 

 

对args.IsValid和this.validator_dcode.IsValid的分析:
args是ServerVlidate事件处理方法的参数, 而this.validator_dcode.IsValid是验证控件上的IsValid属性.
这里又涉及到事件, 上边说过验证事件的处理是在Page_Load事件 --- Page_LoadComplete事件之间, 并且在控件事件之前. 顺便复习下事件, 事件仅仅是个有特殊的委托变量, 该委托变量指向堆中的一个委托对象 ---> 委托对象用来封装方法或函数, 以使我们可以达到传递方法的目的 ---> 但是封装完的方法仅仅是个地址(函数指针), C#不允许直接操作指针 ---> 所以提供了通过"变量名(参数列表)"的方式来调用方法 ---> 也就是"事件(参数列表)" ---> 而调一个空的方法又没有意义, 所以在类中又定义了一个事件触发方法, 判断事件上有方法时(非空)才触发事件. 触发方法格式如下:
protected void On事件名(EventArgs e)
{
    if(事件名 != null)
    {
        事件名(this,e);   //调用委托绑定的方法
    }
}
于是我们知道可以通过"事件(参数列表)"来调用, 而绑定的方法就是我们页面CS文件中的SerVerValidate(object source, ServerValidateEventArgs args). 当控件上触发这个事件时, 与该控件相关的信息都封装在了ServerValidateEventArgs类型的对象args中, 所以我们的事件处理方法中使用的属性都是从args对象里边来的, 当处理方法完成后, 将会根据args对象的结果信息修改控件上的属性, 包括this.validator_dcode.IsValid属性, ErrorMessage的赋值等工作, 因此最终会改掉this.validator_dcode.IsValid属性的值.

posted on 2010-11-12 02:20  RJ  阅读(840)  评论(0编辑  收藏  举报

导航