ASP.NET MVC:如何在服务层执行Data Annotation验证?

时间:2009-10-13 20:25:57

标签: asp.net-mvc asp.net-mvc-2 data-annotations

最近在这里提出的一个问题: ASP.NET MVC: Is Data Annotation Validation Enough?

...得出的结论是,依靠数据注释验证(由模型绑定器触发)不足以确保始终执行验证。我们仍然需要在服务层(或在ModelBinding发生之后的其他地方)添加相同的验证逻辑。不幸的是,我们将复制我们的验证代码(一次使用数据注释,再一次在服务层中)。是否有一种简单的方法让服务层根据数据注释中定义的内容触发验证?如果这是可能的,那么我们将获得两全其美......我们不需要重复验证代码,但我们仍然会确保验证始终执行。

3 个答案:

答案 0 :(得分:4)

在此博客的帮助下:http://goneale.com/2009/03/04/using-metadatatype-attribute-with-aspnet-mvc-xval-validation-framework/ 我能够创建一个方法,根据数据注释定义的验​​证来测试我的对象。它将执行从ValidateAttribute派生的任何验证属性。我现在可以从服务层(或DomainModel)将我的对象传递给此方法,并且我的服务层不再依赖于控制器。这将确保在将数据持久保存到数据库之前始终执行验证。我无法在博客上使用代码,因为我似乎无法访问Graham使用的某些扩展方法,所以这是我的版本:

    public static IList<KeyValuePair<string, string>> GetErrors(object obj)
    {
        // get the name of the buddy class for obj
        MetadataTypeAttribute metadataAttrib = obj.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault() as MetadataTypeAttribute;

        // if metadataAttrib is null, then obj doesn't have a buddy class, and in such a case, we'll work with the model class
        Type buddyClassOrModelClass = metadataAttrib != null ? metadataAttrib.MetadataClassType : obj.GetType();

        var buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass).Cast<PropertyDescriptor>();
        var modelClassProperties = TypeDescriptor.GetProperties(obj.GetType()).Cast<PropertyDescriptor>();

        var errors = from buddyProp in buddyClassProperties
                           join modelProp in modelClassProperties on buddyProp.Name equals modelProp.Name // as this is an inner join, it will return only the properties that are in both the buddy and model classes
                           from attribute in buddyProp.Attributes.OfType<ValidationAttribute>() // get only the attributes of type ValidationAttribute
                           where !attribute.IsValid(modelProp.GetValue(obj))
                           select new KeyValuePair<string, string>(buddyProp.Name, attribute.FormatErrorMessage(string.Empty));

        return errors.ToList();
    }

此代码适用于有和没有好友类的两个类,但如果你不使用好友类,这个代码可以简化一点。 我希望你觉得这很有用。

答案 1 :(得分:0)

您之前的问题中没有检查过my answer吗? 我提交了一些基于DTO的DataAnnotation属性进行自动验证的代码。只要您的控制器操作参数中使用了您的DTO,它们就会被这个属性选中并无论如何都经过验证。

唯一的问题是:您如何生成DTO?

  1. 你自己写的吗?
  2. 您使用EF或类似的东西吗?
  3. 您是否使用其他技术(如T4)自动生成它们?
  4. 如果您可以控制DTO类的生成,那么您也可以为它们添加附加接口。我发布的代码使用T4而不是EF,xVal和DataAnnotation以及声明在每个实体类中实现的Validate()方法的自定义接口。

答案 2 :(得分:0)

我想达到同样的目的并尝试过Johnny的答案。它可以正常工作,直到您具有相对于其他属性的验证,例如使用RequiredIf属性。

我最终在System.ComponentModel.DataAnnotations中使用了Validator类,这实际上就是这个,并且应该应用通常应用的完全相同的完整逻辑。

这是一个示例方法,向您展示如何使用Validator类执行此操作。

    public static bool TryValidate(object obj, List<ValidationResult> results = null)
    {
        var context = new ValidationContext(obj, serviceProvider: null, items: null);
        return Validator.TryValidateObject(obj, context, results, true);
    }