现在的位置: 首页 > 综合 > 正文

MVC3 项目总结

2012年05月23日 ⁄ 综合 ⁄ 共 4483字 ⁄ 字号 评论关闭
  1. 验证 Validation

多样化验证规则

 

最常见的验证方式是:在实体的属性上加 特性(Attribute) 的方式来完成基本的数据验证. 比如 Required, StringLength, Range 等. 为了保持实体类的POCO
( Plain Old CLR Objects
, 所谓的POCO就是那些不包括INSERT、ADD、DEL等数据持久化操作的以及不包括任何业务逻辑功能的原始类。只包含最基本的GETTER 和SETTER).,一般是对实体类声明一个伴随类(MetadataTypeAttribute),在伴随类里声明各种特性.但是伴随类只能声明一个(可以尝试对实体类加多个
MetadataType 看看).

 

实际情况下, 不同的系统可能要求不一样的验证规则,但是又用的是同一套实体.

 

比如旅客信息的邮件地址,电话号码等, 在线下系统下是非必填的,但是在线上预订的时候,又是必填的. 你可以定意两个不同的实体. 我采用的是另外一种方法:

 

先声明一个伴随类:

    public class EContactMetadata {

        [RegularExpression(@"\d{8}" , ErrorMessage = "請輸入8位有效的號碼")]

        [Required]

        public object PhoneNo1 { getset; }

    }

 

在 Global 里把这个伴随类注册到实体类上:

    protected void Application_Start() {
        
        TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(EContact) , typeof(EContactMetadata)) , typeof(EContact));
        
    }

 

用这种方式可以对同一个实体类添加多个伴随类,后注册的会覆盖先注册的.没有发生覆盖的会保留.

 

 

部分验证

某个实体类的属性对应到数据库里的某个字段是必填的,但是在填写界面里,又用不到这个字段,而且这个字段暂时也没有办法生成.

 

比如旅客信息的 OrderNo 是必填的,但是在填写信息页面, OrderNo 还没有生成. 所以在 Action 里, ModelState.IsValid 一直是 false. 为了避免这个 false, 你可以新定义一个类, 但是又不能每一种变化都搞个类出来吧.

 

使用 BindAttribute 接合 ModelBinder

BindAttribute 有 Include 和 Exclude , Include 是只接收 Include 指定的属性, Exclude 是排除.

 

 [HttpPost]
public ActionResult Reserve([Bind(Include = "FG,FB,Hotels,OptionUseDates")]Reserve r , string act) {

 

意思是参数 r 只接收 Post 过来的 FG, FB,Hotels,OptionUseDates 数据,其它的传过来也不要

 

在ModelBinder 中把非 Include 的或 Exclude 的验证错误剔除

 

public class SmartModelBinder : DefaultModelBinder {
    protected override void OnModelUpdated(ControllerContext controllerContext , ModelBindingContext bindingContext) {
        Dictionary<string , bool> startedValid = new Dictionary<string , bool>(StringComparer.OrdinalIgnoreCase);
        //获取模型的验证结果
        var results = ModelValidator.GetModelValidator(bindingContext.ModelMetadata , controllerContext).Validate(bindingContext.Model);

 

        foreach(ModelValidationResult validationResult in results) {
            string subPropertyName = CreateSubPropertyName(bindingContext.ModelName , validationResult.MemberName);

 

            //if(bindingContext.PropertyFilter(subPropertyName)) {
            //bindingContext.PropertyFilter 是一个 delegate, 如果指定的 member  BindAttribute  Include 的列表内(或者非 Exclude 的列表内),返回 true, 否则为 false
            //部分验证的功能就是通过它的结果来实现的
            if(bindingContext.PropertyFilter(validationResult.MemberName)) {
                if(!startedValid.ContainsKey(subPropertyName)) {
                    startedValid[subPropertyName] = bindingContext.ModelState.IsValidField(subPropertyName);
                }

 

                if(startedValid[subPropertyName]) {
                    bindingContext.ModelState.AddModelError(subPropertyName , validationResult.Message);
                }
            }
        }
    }

 

在 Global 里注册该 ModelBinder

protected void Application_Start() {
ModelBinders.Binders.DefaultBinder = new SmartModelBinder();

 

自验证 IValidatableObject

某些情况下,简单的在用 DataAnnoation 不足以做完业务逻辑的验证。比如旅客信息中,儿童的年龄要在返程日期的为准,2 到 11 岁之间, 当机票订票要求是护照时,出生日期、护照号码,签发国家、签发地为必填;当要求是回乡证时,回乡证号必填;当要求护照或回乡证时,其中之一的信息必须完整。

这种情况下,就需要用到 IValidatableObject , 只要按需求实现 Validate 方法就可以了。

 

    public class Traveller : IValidatableObject {
        public int TravellerID { getset; }
        [Required]
        public string FirstName { getset; }
        [Required]
        public string LastName { getset; }

          

        public DateTime Birthday { getset; }

          

        public bool IsAdult { getset; }

 

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
            if(!this.IsAdult && this.Birthday.Date < DateTime.Now.AddYears(-12)) {
                yield return new ValidationResult("儿童年龄必须在 12 岁以内");
            }
        }
    }

 

另外注意,如果标注有 DataAnnation 的属性没有验证没有通过,是不会去执行 Validate 方法的。

 

手动验证

暂未整理

 

启用客服端验证

AppSetting 里

  <!--啟用客戶端校驗-->
  <add key="ClientValidationEnabled" value="true"/>
  <!—启用非介入式验证-->
  <add key="UnobtrusiveJavaScriptEnabled" value="true"/>

Html.EnableClientValidation(true);
Html.EnableUnobtrusiveJavaScript(true)

 

另外,如果以启用了客户端验证,但是表单项并没有在 Form (Html.BeginForm()) 内,也是不会有客户端验证的.

 

自定义客户端验证

具体请参考该 js 文件。

 

以下所述的客户端验证都是基于 jQuery.validate 1.9 + jquery.validate.unobtrusive (项目自带) 的

 

默认的,要在客户端实时看到验证信息(js 验证),需要使用 Html.ValidationMessageFor() 来生成一个容器,供 js 往里填写错误信息.但是,一个页面如果有很多个表单对象,而又不能使用 EditorForModel , 一个一个敲,也是一件很头痛的事。其实可以通过修改,来自动生成: 重写 jQuery validator 的 setting 中的 errorPlacement 和 success 。写这两个是做到最小的修改,如果有必要,你也可以重写 其它的方法。

 

mode1_error 即 errorPlacement

var mode1_error = function(error, inputElement){
    //查找错误提示容器
    var container = $("span[data-valmsg-for='" + inputElement[0].name + "']", inputElement[0].form);

抱歉!评论已关闭.