3

半複雑なシナリオでサーバークライアントの検証ソリューションを完成させるのが苦労しています。 Iは、コアタイプは、DateRange呼ばれています: Semi-Complex View Model ASP.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; } 
} 

をI%mvcproject%\ビュー\共有\ EditorTemplates \ DateRange.cshtmlのような持っている:

@model MyCore.DateRange 

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

また、2つのフォーム入力をDateRangeプロパティにバインドするためのDateRangeModelBinderがあります。私がいる問題は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"; 
    } 
} 

私はそれは2つの入力にフックすることができません。 Split入力のためにEditorTemplateとペアになるのはほぼValidatorTemplateのようなものです。何か案は?追加の説明が必要な場合はお知らせください。

答えて

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

+0

@Darin、FluentValidation.NETのように。しかし、クライアント側の検証は不十分です。どのようにそれを拡張しますか? DataAnnotationベースのバリデーションは、コードが時々クレイジーであっても、拡張することができます。 –