2013-07-22 38 views
3

使用MVC4我需要从自定义ValidationAttribute中检索当前ModelMetadata。原因是验证属性需要知道哪些其他属性被附加到正在验证的特定属性。从验证属性中检索模型元数据

在具体它检查是否有一个UppercaseAttribute附属于它;如果是这种情况,那么它将执行不同的逻辑路径。如果有可能从ValidationAttribute内抢ModelMetadata,我将使用下面的代码来检查它:

ModelMetadata.ContainerType 
    .GetProperty(ViewData.ModelMetadata.PropertyName) 
    .GetCustomAttributes(typeof(UppercaseAttribute), true) 

首先,是有可能从一个自定义ValidationAttribute内检索ModelMetadata。其次,上述代码是检查属性是否具有特定属性的最佳实践。

+0

您是否仅需要此特定型号的验证属性?如果是这样的话,你可以发布你的模型吗? – ataravati

回答

4

这里是你可以做什么:

protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
{ 
    var model = validationContext.ObjectInstance; 

    var displayName = validationContext.DisplayName; 
    var propertyName = model.GetType().GetProperties() 
     .Where(p => p.GetCustomAttributes(false).OfType<DisplayAttribute>().Any(a => a.Name == displayName)) 
     .Select(p => p.Name).FirstOrDefault(); 
    if (propertyName == null) 
     propertyName = displayName; 

    var property = model.GetType().GetProperty(propertyName); 
    var uppercaseAttribute = property.GetCustomAttributes(typeof(UppercaseAttribute), false).SingleOrDefault() as UppercaseAttribute; 

    if (uppercaseAttribute != null) 
    { 
     // some code... 
    } 

    // return validation result... 
} 

出于某种原因,validationContext.MemberName始终为空,所以你必须根据其显示名称来获得属性名。

+0

太棒了!这几乎是我得到的地方,除了由于validationContext.MemberName为空而导致我无法获取属性名称之外。我猜如果显示名称为空,那么它将默认为属性名称? – Jake

+0

是的,如果没有显示名称,validationContext.DisplayName将返回属性名称。 我的答案中的代码唯一的问题是,如果两个属性具有相同的显示名称,它将无法正常工作,但通常情况并非如此。 – ataravati

+0

是的,我注意到了这一点,但我想不出在我的代码中会发生这种情况。 – Jake

2

要回答你的第一个问题:是的。您可以访问ValidationAttribute对象内的ModelMetadata对象。最简单的方法是实现System.Web.Mvc.IMetadataAware接口。该接口有一个名为OnMetadataCreated的方法,它将在验证属性对象上的IsValid方法之前调用。此方法用于接收当前的ModelMetadata对象。以下代码演示了用法:

public class MyCustomValidationAttribute : ValidationAttribute, IMetadataAware 
    { 
     private readonly object _typeId = new object(); 
     private ModelMetadata _metadata; 

     public MyCustomValidationAttribute() 
     { 
     } 

     public override object TypeId 
     { 
      get 
      { 
       return _typeId; 
      } 
     } 

     protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
     { 
      //Do something with the meta data 
      string propertyName = _metadata.PropertyName; 

      return ValidationResult.Success; 
     } 

     public void OnMetadataCreated(ModelMetadata metadata) 
     { 
      _metadata = metadata;   
     } 
    }