[EntLib]微软企业库5.0 学习之路——第六步、使用Validation模块进行服务器端数据验证

      前端时间花了1个多星期的时间写了使用jQuery.Validate进行客户端验证,但是那仅仅是客户端的验证,在开发项目的过程中,客户端的信息永远是不可信的,所以我们还需要在服务器端进行服务器端的验证已保证数据的正确,今天我继续企业库的学习之路,主要介绍企业库中的Validation模块如何对数据进行验证。

本文的主要内容有以下三点:

1、根据本项目进行实体验证。

2、使用Validation提供的ASP.NET控件将实体验证和UI层页面验证联系起来

3、简单分析下Validation.Integration.Aspnet实现逻辑

 

文章开始前的废话

我学习微软企业库都是首先查看企业库提供的HOL(Microsoft Enterprise Library 5.0 - Hands On Labs),里面为企业库的每个模块编写了例子,是非常好的学习材料,而其中的Validation模块的例子是最多的,足足有14个(由此可见Validation模块在企业库中的分量),我看了下,基本上将Validation的各个方面使用方法都介绍了一遍,想学习的朋友可以认真的学习下。

 

第一点:根据本项目进行实体验证

这个项目是一个小型的学生信息管理系统(就是班级和学生简单管理,都不好意思叫系统),主要有班级、学生、科目3个类,我们现在需要通过企业库的Validation模块为这3个类加上验证。

在前几篇文章中,我已经将企业库的Validation模块的各种验证器基本信息进行了介绍,大家可以前往查看

我这边就是将student类进行了简单的验证:

[StringLengthValidator(1, 16,
    MessageTemplate = "登录ID的长度必须在{3}-{5}之间!")]
//MessageTemplateResourceType = typeof(EntLibStudy.Model.Properties.Resources),
//MessageTemplateResourceName = "SidMessage")]
public string Sid
{
    get;
    set;
}
[StringLengthValidator(1, 16,
    MessageTemplateResourceType = typeof(EntLibStudy.Model.Properties.Resources),
    MessageTemplateResourceName = "PasswordMessage")]
public string Password
{
    get;
    set;
}
[StringLengthValidator(1, 16,
    MessageTemplateResourceType = typeof(EntLibStudy.Model.Properties.Resources),
    MessageTemplateResourceName = "NameMessage")]
public string Name
{
    get;
    set;
}

这里我就是将Sid、Password和Name进行必须输入验证。

 

第二点:使用Validation提供的ASP.NET控件将实体验证和UI层页面验证联系起来

在Validation模块中企业库为我们提供了一个子模块——ASP.NET控件用来和Validation模块联合起来进行客户端+服务器端的验证。

我们在页面上放上一个PropertyProxyValidator控件,并指定要验证的控件、对应的实体类型及属性名,具体代码如下:

<tr>
    <td align="right">
        登录ID:
    </td>
    <td>
        <asp:TextBox runat="server" ID="txtSid" />
        <cc1:PropertyProxyValidator ID="PropertyProxyValidator1" runat="server" 
            ControlToValidate="txtSid" PropertyName="Sid"
            SourceTypeName="EntLibStudy.Model.Student,EntlibStudy.Model" ValidationGroup="test"></cc1:PropertyProxyValidator>
    </td>
</tr>
<tr>
    <td align="right">
        密码:
    </td>
    <td>
        <asp:TextBox runat="server" ID="txtPwd" TextMode="Password" />
        <cc1:PropertyProxyValidator ID="PropertyProxyValidator2" runat="server" 
            ControlToValidate="txtPwd" PropertyName="Password"
            SourceTypeName="EntLibStudy.Model.Student,EntlibStudy.Model" ValidationGroup="test"></cc1:PropertyProxyValidator>
    </td>
</tr>
<tr>
    <td align="right">
        姓名:
    </td>
    <td>
        <asp:TextBox runat="server" ID="txtName" />
        <cc1:PropertyProxyValidator ID="PropertyProxyValidator3" runat="server" 
            ControlToValidate="txtName" PropertyName="Name"
            SourceTypeName="EntLibStudy.Model.Student,EntlibStudy.Model" ValidationGroup="test"></cc1:PropertyProxyValidator>
    </td>
</tr>
<tr>

具体有关PropertyProxyValidator控件信息可以看下面的第三点分析,这边仅仅是介绍如何应用。

在页面中添加完指定的控件后,还需要在提交的按钮处做一下处理,代码如下:

protected void btnSubmit_Click(object sender, EventArgs e)
{
    if (!IsValid)
    {
        return;
    }
   //具体业务逻辑
}

这步操作是判断页面验证是否通过,如果验证不通过则返回,主要是因为PropertyProxyValidator控件所依赖的验证都在服务器端,需要点击一次提交按钮来进行验证,所以第一次页面的验证是不通过的,需要等到页面上的所有PropertyProxyValidator控件验证通过后页面的验证才会通过。

这时如果未通过验证,服务器端则会通过PropertyProxyValidator控件将验证消息返回给客户端,见下图, 如果全部填写完整则会真正提交页面信息:

pic35

 

虽然企业库的Validation模块为我们提供了这个ASP.NET控件来和Validation进行组合应用,但是我总觉得不友好(最好能使用AJAX验证来提高界面友好性),而且应用面比较窄(可能还有更好的使用方法我没研究出来,如果有哪位朋友有使用经验欢迎分享),使用起来也不怎么方便,建议还是采用ASP.NET原有的验证控件,在数据提交的时候通过后台代码编写进行验证。

我在网上搜索了相关的文章,认为最好的办法就是为Model层的每个子类都统一继承自一个基类,基类里提供统一的验证方法,这样就可以很好的将验证逻辑封装到Model层,表示层只需在获取到数据后调用这个验证方法,验证不通过则将错误消息返回给客户端,具体代码如下:

namespace EntLibStudy.Helper
{
    [Serializable]
    public abstract class BaseClass<T> where T : class
    {
        public string ValidateTag { get; protected set; }

        public virtual bool IsValid()
        {
            var validateResults = Validation.Validate<T>(this as T);
            if (!validateResults.IsValid)
            {
                foreach (var item in validateResults)
                    string.Format(@"{0}:{1}" + Environment.NewLine, item.Key, item.Message);
                return false;
            }
            return true;
        }
    }
}

修改抽象类BaseClass,同时添加一个属性用于存储验证结果,添加一个方法用于实体验证。

界面使用代码如下:

protected void btnSubmit_Click(object sender, EventArgs e)
{
    //if (!IsValid)
    //{
    //    return;
    //}
    BLL.StudentManage studentBll = new BLL.StudentManage();
    Model.Student student = null;
    try
    {
        int studentId = Convert.ToInt32(this.ViewState["studentId"]);
        if (studentId == 0)
        {
            if (GetValidatedStudent(ref student))
            {
                int id = studentBll.Add(student);
                Helper.Utils.MessageBox(this, "新增学员信息成功!", this.GetRouteUrl("StudentRoute"
                {
                    id = id
                }));
            }
            else
                Helper.Utils.MessageBox(this, student.ValidateTag);
        }
        else
        {
            student = studentBll.SelectById(studentId);
            if (GetValidatedStudent(ref student))
            {
                studentBll.Update(student);
                Helper.Utils.MessageBox(this, "编辑学员信息成功!");
            }
            else
                Helper.Utils.MessageBox(this, student.ValidateTag);
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
}
/// <summary>
/// 获取已验证的学员对象
/// </summary>
/// <param name="student">学员对象</param>
/// <returns>是否验证成功</returns>
private bool GetValidatedStudent(ref Model.Student student)
{
    if (student == null)
    {
        student = new Model.Student();
    }
    student.ClassId = Convert.ToInt32(ddlClass.SelectedValue);
    student.Sid = txtSid.Text.Trim();
    student.Password = txtPwd.Text.Trim();
    student.Name = txtName.Text.Trim();
    student.Sex = Convert.ToInt32(rblSex.SelectedValue);
    student.Birthday = DateTime.Parse(txtBirthday.Text.Trim());

    return student.IsValid();
}

修改了页面的具体代码,添加一个GetValidatedStudent方法用于统一赋值,同时返回实体对象是否验证通过,如不通过则将验证错误消息返回给客户端

 

第三点:简单分析下Validation.Integration.Aspnet实现逻辑

在第二点中已经说过了,Validation.Integration.Aspnet是企业库中Validation模块所提供的一个子模块,其本质是一个ASP.NET控件,核心类就是PropertyProxyValidator.cs,下面我来简单的介绍下这个控件。

PropertyProxyValidator控件其主要作用就是根据配置信息去调用指定的服务器端的验证方法进行验证,如验证不通过则返回验证消息。

类PropertyProxyValidator,继承自ASP.NET中的BaseValidator类,同时实现了接口IValidationIntegrationProxy:

1、BaseValidator类为所有验证控件提供核心实现。验证控件用于验证关联的输入控件中的用户输入。当用户输入的值未通过验证时,验证控件将显示错误信息。由于验证控件是与输入控件分开的,您可以将错误信息定位在页面上相对于输入控件的任意位置。ASP.NET 提供了一些验证控件来执行特定类型的验证。(以上摘自MSDN

由于PropertyProxyValidator继承自BaseValidator类,使得其成为了一个ASP.NET控件(Label控件),基本的客户端验证属性都已经包含在内了。

2、IValidationIntegrationProxy接口是由企业库定义的,其主要作用是为Validation模块提供验证所需行为整合。

在PropertyProxyValidator类中,主要实现了一下方法、属性等:

1、方法BaseValidator.EvaluateIsValid,这个方法的作用是确定输入控件中的值是否有效的代码,其内部实现很简洁,就是创建一个Validator验证器,根据配置通过这个验证器进行验证,然后通过调用内部静态方法FormatErrorMessage来拼装验证返回的消息,最后将这个消息返回给客户端。

PropertyProxyValidator实现的接口IValidationIntegrationProxy主要就为此方法服务,因为创建Validator验证器是通过ValidationIntegrationHelper这个帮助器来创建的,而这个帮助器通过构造函数接收一个实现接口IValidationIntegrationProxy的类,然后帮助器再通过PropertyValidationFactory.GetPropertyValidator属性验证类工厂类中的属性验证器方法调用这个类中所设置好的validatedType(待验证的对象类型)、validatedProperty(待验证的属性信息)、Ruleset(验证规则集)、SpecificationSource(见第5)和ValueAccessBulider(数据访问构造器,这里指向的是类PropertyMappedValidatorValueAccessBuilder)来创建验证器。

2、属性SourceTypeName,待验证对象在服务器端类型,例如:“EntLibStudy.Model.Student,EntLibStudy.Model”,其中逗号前指的是待验证对象所在的类名,逗号后指的是待验证对象所在程序集名。

3、属性PropertyName,待验证对象在服务器端类型中对应的属性名,例如"Name”。

4、属性RulesetName,验证规则集名。

5、属性SpecificationSource,指定的验证信息验证时,调用创建方法所需的源。

6、枚举属性DisplayMode,主要分为3种,List(列表形式)、BulletList(带项目符号的列表形式)和SingleParagraph(段落形式)。

7、事件ValueConvert,用于当控件的值转变时执行验证,对应着委托ValueConverter。

 

以上就是本文的所有内容了,本文主要介绍了企业库的Validation模块中所提供的ASP.NET验证控件。到此企业库的Validation模块就全部介绍完毕了,谢谢大家的浏览。

 

PS:有关在BaseClass中抽象验证参考自:將驗證方法封裝在Model之中(一位台湾的朋友写的)

 

源代码下载:点我下载

 

注意:

1、MSSQL数据库在DataBase目录下(需要自行附加数据库),SQLite数据库在Web目录的App_Data下,由于考虑到项目的大小,所以每个项目的BIN目录都已经删除,如出现无法生成项目请自行添加相关企业库的DLL。

2、由于微软企业库5.0 学习之路这个系列我是准备以一个小型项目的形式介绍企业库的各模块,所以源代码会根据系列文章的更新而更新,所以源代码不能保证与文章中所贴代码相同。

3、项目开发环境为:VS2010+SQL2005。

4、管理员帐户:admin

              密码:admin

 

微软企业库5.0 学习之路系列文章索引:

第一步、基本入门

第二步、使用VS2010+Data Access模块建立多数据库项目

第三步、为项目加上异常处理(采用自定义扩展方式记录到数据库中) 

第四步、使用缓存提高网站的性能(EntLib Caching)

第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——上篇

第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——中篇 

第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——下篇

第六步、使用Validation模块进行服务器端数据验证

第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—上篇

第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—下篇

第八步、使用Configuration Setting模块等多种方式分类管理企业库配置信息

第九步、使用PolicyInjection模块进行AOP—PART1——基本使用介绍

第九步、使用PolicyInjection模块进行AOP—PART2——自定义Matching Rule

第九步、使用PolicyInjection模块进行AOP—PART3——内置Call Handler介绍

第九步、使用PolicyInjection模块进行AOP—PART4——建立自定义Call Handler实现用户操作日志记录

第十步、使用Unity解耦你的系统—PART2——了解Unity的使用方法(1)

第十步、使用Unity解耦你的系统—PART2——了解Unity的使用方法(2)

第十步、使用Unity解耦你的系统—PART3——依赖注入

第十步、使用Unity解耦你的系统—PART4——Unity&PIAB

扩展学习:

扩展学习篇、库中的依赖关系注入(重构 Microsoft Enterprise Library)[转]

 

 

posted @ 2010-08-04 11:14 kyo-yo 阅读(...) 评论(...) 编辑 收藏