使用Controller或View外部的元数据验证对象

时间:2014-02-11 16:23:20

标签: c# asp.net asp.net-mvc validation asp.net-mvc-4

我正在开发一个ASP.NET MVC4 Web应用程序,特别是在一个非常典型的CRUD界面中。

我有一个这样的模型类:

[MetadataType(typeof(USER_Metadata))]
public partial class USER
{
    public class USER_Metadata
    {
        [Required(ErrorMessageResourceName = "MISSING_EMAIL", ErrorMessageResourceType = typeof(Resources.General.Usuario))]
        [StringLength(70, MinimumLength = 3,
                      ErrorMessageResourceName = "EMAIL_LENGTH_ERROR", ErrorMessageResourceType = typeof(Resources.General.Usuario))]
        [DataType(DataType.EmailAddress)]
        public string EMAIL { get; set; }

        /* other, similarly annotated members */
    }

    public string EMAIL { get; set; }
}

我认为这是在MVC中使用的模型类的非常标准的定义。我正在使用该元数据来验证来自ViewPage的用户输入,并且一切都相当容易。

我现在正试图在服务器端验证这个条件(从文件中大量加载用户),我不知道如何从视图外部或控制器中调用这些验证。

我觉得这可能是很多人必须尝试做的事情;我的谷歌可以这么弱吗?这不可能吗?除了使用ModelState在控制器代码中执行此操作,我别无选择吗?

我尝试使用Validator,我认为这是最明显的方式:

var validationResults = new List<System.ComponentModel.DataAnnotations.ValidationResult>();
var isValid = Validator.TryValidateObject(
    instance: user, 
    validationContext: new ValidationContext(user, serviceProvider: null, items: null), 
    validationResults: validationResults,
    validateAllProperties: true);

但这总是让我真实。我也试过使用反射,但无济于事(我的知识在那个区域太浅)。

1 个答案:

答案 0 :(得分:3)

我很好奇这个行为,所以我研究了一下。属性和元数据类将对您的场景(从数据库生成的模型类代码)有所帮助,但考虑到USER不会继承USER_Metadata中的元数据,这些类之间没有链接除了MetadataType属性。由验证码来解释它!

不幸的是,Validator类似乎不尊重[MetadataType]属性,因此您需要手动注册自己。我发现它在SO question中解释了。所以只要你有一个元数据类就会发生这个问题,它是否嵌套并不重要。

根据该答案,您可以使用以下行注册您的元数据类(使用USER类和嵌套的USER_Metadata元数据类的原始示例):

TypeDescriptor.AddProviderTransparent(
     new AssociatedMetadataTypeTypeDescriptionProvider(typeof(USER), typeof(USER.USER_Metadata)), typeof(USER)); 

快速而肮脏的方法是确保在验证对象之前调用该行,如:

TypeDescriptor.AddProviderTransparent(
     new AssociatedMetadataTypeTypeDescriptionProvider(typeof(USER), typeof(USER.USER_Metadata)), typeof(USER));
var validationResults = new List<System.ComponentModel.DataAnnotations.ValidationResult>();
var isValid = Validator.TryValidateObject(
    instance: user, 
    validationContext: new ValidationContext(user, serviceProvider: null, items: null), 
    validationResults: validationResults,
    validateAllProperties: true);

但是,您可以编写一些反射代码并在程序集中注册所有元数据类,作为应用程序初始化的一部分。类似的代码已经写在this other SO question

希望它有所帮助!