2010-11-24 49 views
9

我通過繼承ValidationAttribute來創建自定義驗證屬性。該屬性應用於我的視圖模型在類級別,因爲它需要驗證多個屬性。無法從MVC2中的自定義驗證屬性設置成員名稱

我重寫

protected override ValidationResult IsValid(object value, ValidationContext validationContext) 

並返回:

new ValidationResult("Always Fail", new List<string> { "DateOfBirth" }); 
在所有情況下,出生日期是在我的視圖模型的屬性之一

當我運行我的應用程序時,我可以看到這個打擊。 ModelState.IsValid設置爲false,但當我檢查ModelState內容時,我發現Property DateOfBirth不包含任何錯誤。相反,我有一個空字符串鍵值爲null,並且包含我在我的驗證屬性中指定的字符串的異常。

這會導致在使用ValidationMessageFor時,我的UI中不會顯示任何錯誤消息。如果我使用ValidationSummary,那麼我可以看到錯誤。這是因爲它與一個屬性沒有關聯。

它看起來好像忽略了我在驗證結果中指定了成員名的事實。

這是爲什麼?如何解決?

示例代碼的要求:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] 
    public class ExampleValidationAttribute : ValidationAttribute 
    { 
     protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
     { 
      // note that I will be doing complex validation of multiple properties when complete so this is why it is a class level attribute 
      return new ValidationResult("Always Fail", new List<string> { "DateOfBirth" }); 
     } 
    } 

    [ExampleValidation] 
    public class ExampleViewModel 
    { 
     public string DateOfBirth { get; set; } 
    } 

回答

2

我不知道一個簡單的方法解決這個問題。這是我討厭數據註釋的原因之一。做同樣與FluentValidation將蛋糕和平:

public class ExampleViewModelValidator: AbstractValidator<ExampleViewModel> 
{ 
    public ExampleViewModelValidator() 
    { 
     RuleFor(x => x.EndDate) 
      .GreaterThan(x => x.StartDate) 
      .WithMessage("end date must be after start date"); 
    } 
} 

FluentValidation有很大support and integration with ASP.NET MVC

+3

謝謝。所以MVC團隊正在重新使用ValidationResult類,但完全忽略了其中一個屬性?總的來說,MVC團隊的輸出讓我印象深刻,但這很糟糕。我只是在MVC3/.NET4中檢查過它,它仍然是一樣的。 – 2010-11-24 13:02:45

-1

您需要設置ErrorMessage屬性,因此,例如:

public class DOBValidAttribute : ValidationAttribute 
{ 
    private static string _errorMessage = "Date of birth is a required field."; 

    public DOBValidAttribute() : base(_errorMessage) 
    { 

    } 
//etc......overriding IsValid.... 
+0

錯誤消息正在設置,並通過罰款,如上所述。問題在於應該映射到ModelState中的鍵的成員名稱。 – 2010-11-24 12:30:14

+0

那麼您可以發佈您的代碼嗎,這可能會使我們更容易幫助 – ozz 2010-11-24 12:32:53

13

大家好。

仍在尋找解決方案?

我今天解決了同樣的問題。你必須創建自定義驗證屬性來驗證兩個日期(下面的例子)。然後你需要Adapter(驗證器),它將用你的自定義屬性驗證模型。最後一件事是綁定適配器和屬性。也許一些例子更好地解釋它比我:)

這裏,我們去:

DateCompareAttribute.cs:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] 
public class DateCompareAttribute : ValidationAttribute 
{ 
    public enum Operations 
    { 
     Equals,    
     LesserThan, 
     GreaterThan, 
     LesserOrEquals, 
     GreaterOrEquals, 
     NotEquals 
    }; 

    private string _From; 
    private string _To; 
    private PropertyInfo _FromPropertyInfo; 
    private PropertyInfo _ToPropertyInfo; 
    private Operations _Operation; 

    public string MemberName 
    { 
     get 
     { 
      return _From; 
     } 
    } 

    public DateCompareAttribute(string from, string to, Operations operation) 
    { 
     _From = from; 
     _To = to; 
     _Operation = operation; 

     //gets the error message for the operation from resource file 
     ErrorMessageResourceName = "DateCompare" + operation.ToString(); 
     ErrorMessageResourceType = typeof(ValidationStrings); 
    } 

    public override bool IsValid(object value) 
    { 
     Type type = value.GetType(); 

     _FromPropertyInfo = type.GetProperty(_From); 
     _ToPropertyInfo = type.GetProperty(_To); 

     //gets the values of 2 dates from model (using reflection) 
     DateTime? from = (DateTime?)_FromPropertyInfo.GetValue(value, null); 
     DateTime? to = (DateTime?)_ToPropertyInfo.GetValue(value, null); 

     //compare dates 
     if ((from != null) && (to != null)) 
     { 
      int result = from.Value.CompareTo(to.Value); 

      switch (_Operation) 
      { 
       case Operations.LesserThan: 
        return result == -1; 
       case Operations.LesserOrEquals: 
        return result <= 0; 
       case Operations.Equals: 
        return result == 0; 
       case Operations.NotEquals: 
        return result != 0; 
       case Operations.GreaterOrEquals: 
        return result >= 0; 
       case Operations.GreaterThan: 
        return result == 1; 
      } 
     } 

     return true; 
    } 

    public override string FormatErrorMessage(string name) 
    { 
     DisplayNameAttribute aFrom = (DisplayNameAttribute)_FromPropertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault(); 
     DisplayNameAttribute aTo = (DisplayNameAttribute)_ToPropertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), true).SingleOrDefault(); 

     return string.Format(ErrorMessageString, 
      !string.IsNullOrWhiteSpace(aFrom.DisplayName) ? aFrom.DisplayName : _From, 
      !string.IsNullOrWhiteSpace(aTo.DisplayName) ? aTo.DisplayName : _To); 
    } 
} 

DateCompareAttributeAdapter.cs:

public class DateCompareAttributeAdapter : DataAnnotationsModelValidator<DateCompareAttribute> 
{ 
    public DateCompareAttributeAdapter(ModelMetadata metadata, ControllerContext context, DateCompareAttribute attribute) 
     : base(metadata, context, attribute) { 
    } 

    public override IEnumerable<ModelValidationResult> Validate(object container) 
    { 
     if (!Attribute.IsValid(Metadata.Model)) 
     { 
      yield return new ModelValidationResult 
      { 
       Message = ErrorMessage, 
       MemberName = Attribute.MemberName 
      }; 
     } 
    } 
} 

的Global.asax:

protected void Application_Start() 
{ 
    // ... 
    DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(DateCompareAttribute), typeof(DateCompareAttributeAdapter)); 
} 

CustomViewModel。cs:

[DateCompare("StartDateTime", "EndDateTime", DateCompareAttribute.Operations.LesserOrEquals)] 
public class CustomViewModel 
{ 
    // Properties... 

    public DateTime? StartDateTime 
    { 
     get; 
     set; 
    } 

    public DateTime? EndDateTime 
    { 
     get; 
     set; 
    } 
} 
0

當返回驗證結果時,使用兩個參數構造函數。 將context.MemberName作爲唯一值傳遞給一個數組。 希望這有助於

<AttributeUsage(AttributeTargets.Property Or AttributeTargets.Field, AllowMultiple:=False)> 


Public Class NonNegativeAttribute 
Inherits ValidationAttribute 
Public Sub New() 


End Sub 
Protected Overrides Function IsValid(num As Object, context As ValidationContext) As ValidationResult 
    Dim t = num.GetType() 
    If (t.IsValueType AndAlso Not t.IsAssignableFrom(GetType(String))) Then 

     If ((num >= 0)) Then 
      Return ValidationResult.Success 
     End If 
     Return New ValidationResult(context.MemberName & " must be a positive number",  New String() {context.MemberName}) 

    End If 

    Throw New ValidationException(t.FullName + " is not a valid type. Must be a number") 
End Function 

End Class 
相關問題