Asp.net-Mvc

無法從 MVC2 中的自定義驗證屬性設置成員名

  • February 12, 2014

我通過繼承 ValidationAttribute 創建了一個自定義驗證屬性。該屬性在類級別應用於我的視圖模型,因為它需要驗證多個屬性。

我壓倒一切

protected override ValidationResult IsValid(object value, ValidationContext validationContext)

並返回:

new ValidationResult("Always Fail", new List<string> { "DateOfBirth" }); 

在 DateOfBirth 是我的視圖模型上的屬性之一的所有情況下。

當我執行我的應用程序時,我可以看到它受到了影響。ModelState.IsValid 正確設置為 false,但是當我檢查 ModelState 內容時,我看到 Property DateOfBirth 不包含任何錯誤。相反,我有一個值為 null 的空字元串 Key 和一個包含我在驗證屬性中指定的字元串的異常。

這導致在使用 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; }
   }

我不知道解決此行為的簡單方法。這就是我討厭數據註釋的原因之一。對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 對ASP.NET MVC 有很好的支持和集成

大家好。

還在尋找解決方案?

我今天解決了同樣的問題。您必須創建將驗證 2 個日期的自定義驗證屬性(範例如下)。然後您需要適配器(驗證器),它將使用您的自定義屬性驗證模型。最後一件事是將適配器與屬性綁定。也許一些例子會比我解釋得更好:)

開始了:

日期比較屬性.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
           };
       }
   }
}

全球突擊:

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;
   }
}

引用自:https://stackoverflow.com/questions/4266632