3

我很努力爲半複雜場景完成服務器 - 客戶端驗證解決方案。我有一個芯型稱爲DateRangeASP.NET MVC中的半複雜視圖模型屬性驗證3

public class DateRange { 
    public DateRange (DateTime? start, DateTime? end) { ... } 
    public DateTime? Start { get; private set; } 
    public DateTime? End { get; private set; } 
} 

我有這樣一個視圖模型:

public class MyViewModel { 
    public DateRange Period { get; set; } 
} 

我有個%mvcproject%\視圖\共享\ EditorTemplates \ DateRange.cshtml像:

@model MyCore.DateRange 

@Html.Editor("Start", "Date") 
@Html.Editor("End", "Date") 

我也有一個DateRangeModelBinder將兩個表單輸入綁定到DateRange屬性。我遇到的問題是一個DateRangeRequiredAttribute

public class DateRangeRequired : ValidationAttribute, IClientValidatable, 
    IMetadataAware 
{ 
    private const string DefaultErrorMessage = 
      "{0} is required."; 

    public DateRangeRequired(bool endIsRequired = true) 
     : base(() => DefaultErrorMessage) 
    { 
     EndIsRequired = endIsRequired; 
    } 

    public bool EndIsRequired { get; set; } 

    public override bool IsValid(object value) 
    { 
     if (value == null) 
     { 
      return false; 
     } 
     if (!value.GetType().IsAssignableFrom(typeof(DateRange))) 
     { 
      throw new ArgumentException("Value is not a DateRange."); 
     } 
     var dateRange = value as DateRange; 
     return (dateRange.Start.HasValue && !EndIsRequired) || 
       (dateRange.Start.HasValue && dateRange.End.HasValue && EndIsRequired); 
    } 

    public override string FormatErrorMessage(string name) 
    { 
     return string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name); 
    } 

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     var rule = new ModelClientValidationRule() 
     { 
      ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), 
      ValidationType = "daterangerequired" 
     }; 
     rule.ValidationParameters.Add("endisrequired", EndIsRequired.ToString().ToLower()); 
     yield return rule; 
    } 

    public void OnMetadataCreated(ModelMetadata metadata) 
    { 
     metadata.DataTypeName = "DateRange"; 
    } 
} 

我不能讓它掛鉤到兩個輸入。這幾乎就像需要有一個ValidatorTemplate與EditorTemplate配對,因爲分割輸入。有任何想法嗎?讓我知道是否需要額外澄清。

回答

3

您還沒有確切顯示DateRangeRequiredAttribute如何實現自定義的樣子,所以讓我提出一個例子:

public class DateRangeRequiredAttribute : ValidationAttribute, IClientValidatable 
{ 
    private readonly string _otherProperty; 
    public DateRangeRequiredAttribute(string otherProperty) 
    { 
     _otherProperty = otherProperty; 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     var property = validationContext.ObjectType.GetProperty(_otherProperty); 
     if (property == null) 
     { 
      return new ValidationResult(string.Format(CultureInfo.CurrentCulture, "Unknown property {0}", _otherProperty)); 
     } 
     var otherValue = property.GetValue(validationContext.ObjectInstance, null); 
     if (!(value is DateTime) || !(otherValue is DateTime)) 
     { 
      return new ValidationResult(string.Format(CultureInfo.CurrentCulture, "The two properties to compare must be of type DateTime")); 
     } 

     if ((DateTime)value >= (DateTime)otherValue) 
     { 
      return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); 
     } 
     return null; 
    } 

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     var rule = new ModelClientValidationRule 
     { 
      ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), 
      ValidationType = "daterange" 
     }; 
     rule.ValidationParameters.Add("other", "*." + _otherProperty); 
     yield return rule; 
    } 
} 

,那麼你可以用它裝點您的視圖模型:

public class DateRange 
{ 
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")] 
    [DateRangeRequired("End", ErrorMessage = "Please select a start date before the end date")] 
    public DateTime? Start { get; set; } 

    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")] 
    [Required] 
    public DateTime? End { get; set; } 
} 

和最後在視圖中註冊適配器:

​​

看完這個色情內容後,你可能會考慮使用FluentValidation.NET,這使得這個非常簡單的驗證方案實現了幾行代碼(這就是這樣簡單的驗證方案應該如何完成)。我會強烈建議你這個庫。我在我的所有項目中都使用它,因爲我厭倦了DataAnnotations進行驗證。他們非常有限。

+0

這看起來不錯,是完整的。然而,這不是我想要用我的屬性來做的。 DateRange不是視圖模型,並且不是每個具有DateRange屬性的視圖模型都需要結束日期。我會發布我的屬性代碼進行澄清。 – gabe 2011-12-21 20:49:21

+0

@Darin,就像FluentValidation.NET一樣。但是,缺乏客戶端驗證。你如何擴展它?即使代碼有時是瘋狂的,基於DataAnnotation的驗證也可以被擴展。 – 2012-02-16 23:05:49