7.2 扩展验证控件的功能
在了解了ASP.NET验证控件框架之后,我们实现一个验证密码安全强度的PasswordStrenthValidator验证控件。该控件继承自BaseValidator,并同时实现客户端和服务端的验证功能。
PasswordStrenthValidator验证控件的验证计算逻辑比较复杂:
密码中的数字,小写字母,大写字母每个计强度分5分;
密码中的标点符号每个计强度分10分;
每增加一种字符类型,加20分强度分,比如密码中同时有数字、小写字母和标点符号,则可加上类型分40分。
7.2.1 客户端验证
我们首先来实现客户端验证的脚本。在控件项目中新建一个脚本文件,PasswordStrenth.js,并将其设为内嵌的资源。
var PasswordStrenthValidatorEvaluateIsValid =
function PasswordStrenthValidator$EvaluateIsValid(val){
var controlValue =
ValidatorTrim(ValidatorGetValue(val.controltovalidate));
var strenthValue = 0;
var multiType = -1;
var rules = PasswordStrenthValidatorEvaluateIsValid.rules;
for(var i = 0 ; i < rules.length ; i++){
var matchCount = PasswordStrenthValidatorEvaluateIsValid
._getMatchCount(rules[i].regex,controlValue);
strenthValue += matchCount * rules[i].ratio;
if(matchCount){
multiType ++;
}
}
strenthValue +=
PasswordStrenthValidatorEvaluateIsValid.multiType * multiType;
return (strenthValue >= val.passwordStrenth);
}
PasswordStrenthValidatorEvaluateIsValid._getMatchCount =
function Validator$getMatchCount(reg,value){
var cnt = 0;
while (reg.exec(value) != null)
{
cnt++;
}
return cnt;
}
PasswordStrenthValidatorEvaluateIsValid.multiType = 20;
PasswordStrenthValidatorEvaluateIsValid.rules = [
{
regex:new RegExp("[a-z]", "g"),
ratio:5
},
{
regex:new RegExp("[0-9]", "g"),
ratio:5
},
{
regex:new RegExp("[A-Z]", "g"),
ratio:5
},
{
regex:new RegExp("[^a-z,A-Z,0-9,\x20]", "g"),
ratio:10
}];
实际执行验证时,传递给PasswordStrenthValidatorEvaluateIsValid()的val参数为验证控件呈现的DOM对象,该对象会扩展很多属性,包括controltovalidate、passwordStrenth等。在这段代码中我们使用了验证控件框架本身的资源脚本文件中的一些方法,比如用来去除字符串首尾空白字符的ValidatorTrim()方法,用来获得被验证元素的ValidatorGetValue()方法。
7.2.2 组织服务端
准备好了客户端验证所需的脚本文件后,我们还需要指定PasswordStrenthValidator控件使用PasswordStrenthValidatorEvaluateIsValid()函数进行客户端验证。此外,验证通过与否的对照强度值也需要呈现到客户端,所以我们重写了相关的呈现逻辑:
[assembly: WebResource("CustomValidators.PasswordStrenth.js",
"application/x-javascript")]
namespace CustomValidators
{
[ToolboxData("<{0}:PasswordStrenthValidator runat=\"server\"
ErrorMessage=\"PasswordStrenthValidator\">
</{0}:PasswordStrenthValidator>")]
public class PasswordStrenthValidator:BaseValidator
{
// *** ***
[Category("Behavior")]
[DefaultValue(60)]
public int PassWordStrenth
{
get
{
if (ViewState["PassWordStrenth"] == null)
return 60;
return (int)ViewState["PassWordStrenth"];
}
set
{
ViewState["PassWordStrenth"] = value;
}
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (!DesignMode)
{
Page.ClientScript.RegisterClientScriptResource(
typeof(PasswordStrenthValidator),
"CustomValidators.PasswordStrenth.js");
}
}
protected override void AddAttributesToRender(
System.Web.UI.HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
if (base.RenderUplevel)
{
string controlId = ClientID;
Page.ClientScript.RegisterExpandoAttribute(ClientID,
"evaluationfunction",
"PasswordStrenthValidatorEvaluateIsValid", false);
Page.ClientScript.RegisterExpandoAttribute(ClientID,
"passwordStrenth",
this.PassWordStrenth.ToString(),false);
}
}
}
}
在OnPreRender()方法中,我们将内嵌脚本PasswordStrenth.js注册到页面中。在AddAttributesToRender()方法中,我们为客户端控件添加了evaluationfunction和PasswordStrenthValidatorEvaluateIsValid两个扩展属性。
PasswordStrenthValidator本身也实现了和客户端同样的验证的逻辑:
public class PasswordStrenthValidator:BaseValidator
{
static Regex[] _regexes =
{ new Regex("[a-z]", RegexOptions.Compiled),
new Regex("[A-Z]",RegexOptions.Compiled),
new Regex("[0-9]",RegexOptions.Compiled),
new Regex(@"[^a-z,A-Z,0-9,\x20]",
RegexOptions.Compiled)
};
static int[] _ratio = { 5, 5, 5, 10 };
static readonly int _multiType = 20;
[Category("Behavior")]
[DefaultValue(60)]
public int PassWordStrenth
{
get
{
if (ViewState["PassWordStrenth"] == null)
return 60;
return (int)ViewState["PassWordStrenth"];
}
set
{
ViewState["PassWordStrenth"] = value;
}
}
protected override bool EvaluateIsValid()
{
string value = GetControlValidationValue(ControlToValidate);
if (value == null && value.Trim() == string.Empty)
return true;
int strenthValue = 0;
int multiType = -1;
for (int i = 0; i < _regexes.Length; i++)
{
Regex reg = _regexes[i];
int matchCount = reg.Matches(value).Count;
strenthValue += matchCount * _ratio[i];
if (matchCount > 0)
{
multiType++;
}
}
strenthValue += multiType * _multiType;
return strenthValue >= PassWordStrenth;
}
}
}
可以看到基于BaseValidator实现自定义验证控件是一件非常惬意的事情,基本上,你只需关注验证逻辑的实现即可。最终运行效果如图7-2所示。
![]()
图7-2 密码强度验证控件







