【问题标题】:Validation does not work when I use Validator.TryValidateObject当我使用 Validator.TryValidateObject 时验证不起作用
【发布时间】:2011-01-26 04:39:26
【问题描述】:

DataAnnotations 不适用于伙伴类。以下代码始终验证为真。为什么?

var isValid = Validator.TryValidateObject(new Customer(), Context, results, true);

这里是伙伴班。

public partial class Customer 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
}

[MetadataType(typeof(CustomerMetaData))]
public partial class Customer 
{ 
    public class CustomerMetaData 
    { 
        [Required(ErrorMessage = "You must supply a name for a customer.")]        
        public string Name { get; set; } 
    } 
}

这是另一个有相同问题的线程。但没有答案。 link text

【问题讨论】:

  • 我对此并不担心,但我认为您不应该嵌套类。此外,我认为如果没有公共关键字,这可能会使 CustomMetaData 类无法访问。尝试将 CustomerMetaData 移出 Customer 类并将其公开。
  • 即使我将 CustomerMetaData 移出 Customer 类并声明为 public,它也不起作用。我担心 TryValidateObject 是否支持 buddyclass (MetadataType)?

标签: asp.net-mvc silverlight .net-4.0 data-annotations buddy-class


【解决方案1】:

存在对象上下文无法识别 MetadataType 属性的问题。虽然您可以在验证之前手动添加类型描述符: TypeDescriptor.AddProviderTransparent( new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Customer), typeof(CustomerMetaData)), typeof(Customer));

更简洁的处理方法是更新实体模型 .tt 文件,将以下内容添加到每个 DTO:

    Type currentType = MethodBase.GetCurrentMethod().DeclaringType;
    object[] attributes = currentType.GetCustomAttributes(typeof(MetadataTypeAttribute),false);
    if(attributes.Length > 0)
    {
        //MetadataType attribute found!
        MetadataTypeAttribute metaDataAttribute = (MetadataTypeAttribute)attributes[0];
        TypeDescriptor.AddProviderTransparent(
            new AssociatedMetadataTypeTypeDescriptionProvider(
                currentType, metaDataAttribute.MetadataClassType),currentType);
    }

这将允许您将属性添加到部分类:

[MetadataType(typeof(CustomerMetaData))]
public partial class Customer
{

}

public partial class CustomerMetaData
{
    [Required]
    public string CustomerName { get; set; }
}

【讨论】:

  • 你好@Gareth Suarez,我认为这是个好主意,你能提供更多关于如何编辑 Entity Model.tt 文件的信息吗?
  • 我实际上尝试过这样做,但我不知道我应该在哪里包含您的 sn-p。我尝试将它包含在每个 DTO 的构造函数中,但我一点运气都没有。任何想法?顺便说一句,我正在尝试通过 MetadataType 在某些属性中设置 IgnoreDataMember,这种方法应该可以工作,对吧?
【解决方案2】:

我在这里找到了答案:http://forums.silverlight.net/forums/p/149264/377212.aspx

MVC 识别 MetaDataType 属性,但其他项目不识别。在验证之前,需要手动注册元数据类:

TypeDescriptor.AddProviderTransparent(
            new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Customer), typeof(CustomerMetadata)), typeof(Customer));

var isValid = Validator.TryValidateObject(new Customer(), context, results, true);

【讨论】:

  • 谢谢。如果我选择数据注释作为我的验证框架,那么 Validator.TryValidaeObject 应该从任何地方验证。
  • AssociatedMetadataTypeTypeDescriptionProvider 类的无构造函数重载需要三个参数。我在代码 sn-p 中看到了这个问题。
  • 我犯的错误是在使用TypeDescriptor.AddProviderTransparent 调用。 AddProviderTransparent 有两个重载。它们的第二个参数不同。最初我试图使用带有对象参数的那个。它没有用。当我用具有 Type 参数的第二个重载替换它时,它就起作用了。我想知道为什么第一次重载不起作用:public static void AddProviderTransparent(TypeDescriptionProvider provider, object instance); public static void AddProviderTransparent(TypeDescriptionProvider provider, Type type);
【解决方案3】:

经过一些研究,如果我使用 MetadataType(伙伴类),我找不到任何 TryValidateObject 总是返回 true 的原因。但它适用于以下代码(xVal)。

    public static IEnumerable<ErrorInfo> GetErrors(object instance, string name)
    {
        var metadataAttrib = instance.GetType()
                .GetCustomAttributes(typeof(MetadataTypeAttribute), true)
                .OfType<MetadataTypeAttribute>().FirstOrDefault();
        var buddyClassOrModelClass = metadataAttrib != null
                ? metadataAttrib.MetadataClassType
                : instance.GetType();
        var buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass)
            .Cast<PropertyDescriptor>();
        var modelClassProperties = TypeDescriptor.GetProperties(instance.GetType())
            .Cast<PropertyDescriptor>();

        var list = from buddyProp in buddyClassProperties
                   join modelProp in modelClassProperties on
                            buddyProp.Name equals modelProp.Name
                   from attribute in buddyProp.Attributes.OfType<ValidationAttribute>()
                   where !attribute.IsValid(modelProp.GetValue(instance))
                   select new ErrorInfo(
                       buddyProp.Name,
                       attribute.FormatErrorMessage(modelProp.Name),
                       instance);

        if (name != null)
            list = list.Where(x => x.PropertyName == name);

        return list;
    }

【讨论】:

    【解决方案4】:

    虽然我没有在 .NET 4.0 中测试您的代码,但在 .NET 3.5 / Silverlight 3 中,您的元数据类应该如下所示:

    [MetadataType(typeof(Customer.CustomerMetaData))]
    public partial class Customer 
    { 
        internal sealed class CustomerMetaData 
        {
            private CustomerMetaData()
            {
            }
    
            [Required(ErrorMessage = "You must supply a name for a customer.")]        
            public string Name; 
        } 
    }
    

    【讨论】:

      猜你喜欢
      • 2011-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多