频道栏目
读书频道 > web开发 > .NET > ASP.NET MVC 3高级编程
13.1.3 验证模型
2013-01-10 11:11:51     我来说两句
收藏   我要投稿

本文所属图书 > ASP.NET MVC 3高级编程

ASP.NET MVC 3是由Microsoft公司推出的、万众期待的用来创建数据驱动型动态Web应用程序的最新框架。本书由Microsoft公司内部团队编写,深入阐述了如何利用ASP.NET MCV 3的新特性及其激动人心的功能。本书首先...  立即去当当网订购

模型验证在ASP.NET MVC中已经引入,但是直到ASP.NET MVC 2时才引入可插拔的验证提供器。ASP.NETMVC是验证基于接口IdataErrorInfo的,尽管该接口仍然可以使用,但是开发人员应该考虑废弃它。使用ASP.NETMVC 2及其以后版本的开发人员可以在模型属性上使用DataAnnotations验证特性。.NET 3.5 SP1包含4个验证特性:[Required]、[Range]、[StringLength] 和[Regular Expression]。开发人员可以使用基类ValidationAttribute来编写自定义的验证逻辑。

CLR团队在.NET 4中对验证系统添加了一些新的增强,其中包括新的IValidatableObject接口。ASP.NET MVC 3添加了两个新的验证器:[Compare]和[Remote]。除此之外,为了与使用jQuery Validate的新验证规则集相匹配,开发团队还在ASP.NETMVC特性中引入了一些验证器,其中包括[CreditCard]、[Email]、[FileExtension]和[Url]。

第6章已深入地介绍了如何编写自定义验证器,这里不再重复。相反,这里重点探讨编写验证器提供器更高级的主题。验证器提供器允许开发人员引入新的验证源。在ASP.NET MVC 3中,默认安装了3个验证器提供器:

DataAnnotationsModelValidatorProvider支持继承自ValidationAttribute的验证器和实现了接口IValidatableObject的模型。

DataErrorInfoModelValidatorProvider支持实现了由ASP.NETMVC的验证层使用的Idata ErrorInfo接口的类。

ClientDataTypeModelValidatorProvider提供了客户端验证对内置数字数据类型的支持,像整数、小数和浮点数等。

实现验证器提供器意味着需要继承基类ModelValidatorProvider,并实现返回给定模型的验证器的方法,给定模型由ModelMetadata的一个实例和ControllerContext表示。我们可以通过使用ModelValidatorProviders.Providers来注册自定义的模型验证器提供器。

在目录~/Areas/FluentValidation下的示例代码中有一个变数模型验证系统的例子。几乎和变数模型元数据的例子一样,它也是相当复杂的,因为它需要提供一些验证函数,但是实现验证提供器的大部分代码还是相当简单明了的。

该例在区域注册函数的内部包括变数验证注册:
ModelValidatorProviders.Providers.Add(
   new FluentValidationProvider()
        .ForModel<Contact>()
           .ForProperty(c => c.FirstName)
                    .Required()
                    .StringLength(maxLength: 15)
               .ForProperty(c => c.LastName)
                    .Required(errorMessage: "You must provide the last name!")
                    .StringLength(minLength: 3, maxLength: 20)
           .ForProperty(c => c.EmailAddress)
                    .Required()
                    .StringLength(minLength: 10)
                    .EmailAddress()
);

对于该例,我们已经实现了三个不同的验证器,其中既包括服务器端的验证支持,也包括客户端的验证支持。注册API看起来和以前检查的模型元数据变数API几乎相同。GetValidators的实现基于一个从请求类型和可选属性名称映射到验证器工厂的一个字典:
public override IEnumerable<ModelValidator> GetValidators(
        ModelMetadata metadata,
        ControllerContext context) {
   IEnumerable<ModelValidator>
results = Enumerable.Empty<ModelValidator>();
   if (metadata.PropertyName != null)
        results = GetValidators(metadata,
                                       context,
                               metadata.ContainerType,
                               metadata.PropertyName);
   return results.Concat(
        GetValidators(metadata,
                           context,
                           metadata.ModelType)
   );
}

不像模型元数据,ASP.NETMVC框架支持多个验证提供器,所以我们没有必要继承或委托现有的验证提供器。我们只需要添加自己合适的唯一的验证规则。适用于特定属性的验证器是那些也适用于属性自身和它的类型的验证器,例如,假设有如下模型:
public class Contact
{
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public string EmailAddress { get; set; }
}

当为FirstName请求验证规则时,系统会提供那些适用于FirstName属性自身或System.String(因为这是FirstName的类型)的规则。

上面例子中使用的私有GetValidators方法的实现经过修改后,代码如下:
private IEnumerable<ModelValidator> GetValidators(
        ModelMetadata metadata,
        ControllerContext context,
        Type type,
        string propertyName = null)
{
    var key = new Tuple<Type, string>(type, propertyName);
    List<ValidatorFactory> factories;
    if (validators.TryGetValue(key, out factories))
       foreach (var factory in factories)
            yield return factory(metadata, context);
}

修改后的代码将查找已经使用提供器注册的所有验证器工厂。我们在注册中看到的像Required和StringLength等函数是用来注册这些验证器工厂的。所有这些函数往往都遵循相同的模式,如下所示:
public ValidatorRegistrar<TModel> Required(
        string errorMessage = "{0} is required")
{
   provider.Add(
          typeof(TModel),
        propertyName,
        (metadata, context) =>
           new RequiredValidator(metadata, context, errorMessage)
   );

   return this;
}

provider.Add调用的第三个参数是作为验证器工厂的匿名函数。输入模型元数据和控制器上下文,它将返回一个继承了ModelValidator类的实例。

MVC可以理解基类ModelValidator,并使用它来进行验证。我们可以在前面模型绑定器的示例中看到ModelValidator 类的隐式用法,因为当创建和绑定对象时,最终是由模型绑定器负责执行验证。我们正在使用的RequiredValidator实现有两个主要任务:执行服务器端验证和返回关于客户端验证的元数据,实现代码如下所示:
private class RequiredValidator : ModelValidator {
   private string errorMessage;
   public RequiredValidator(ModelMetadata metadata,
                                   ControllerContext context,
                             string errorMessage) : base(metadata, context)
{
        this.errorMessage = errorMessage;
   }
    private string ErrorMessage {
       get {
            return String.Format(errorMessage, Metadata.GetDisplayName());
       }
    }
    public IEnumerable<ModelClientValidationRule>
GetClientValidationRules() {
       yield return new ModelClientValidationRequiredRule(ErrorMessage);
    }
    public IEnumerable<ModelValidationResult> Validate(object container) {
       if (Metadata.Model == null)
            yield return new ModelValidationResult { Message = ErrorMessage };
      }
}

整个示例包括三个验证规则(Required、StringLength和EmailAddress)的实现,涵盖了模型、控制器和视图,展示了它们一起工作的情境。客户端验证被默认关闭,以便验证和调试服务器端验证。当然,我们可以从视图中删除那行代码来重新启用客户端验证,以了解它的工作原理。

您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:13.1.2 用元数据描述模型
下一篇:13.2.1 自定义视图引擎
相关文章
图文推荐
排行
热门
最新书评
文章
下载
读书
特别推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站