16

私は私のモデル上の2つの他の値の範囲内に入らなければならない私のモデル上の値を、持っています。例えばMVC控えめな範囲の検証

:彼らは一定の値であることが持っているとしてもちろん

public class RangeValidationSampleModel 
{ 
    int Value { get; set; } 

    int MinValue { get; set; } 

    int MaxValue { get; set; } 
} 

、私は、私のDataAnnotations属性にこれらの最小/ MaxValuesを渡すことはできません。

私は私の独自の検証属性を構築する必要があります確信しているが、私はこれだけを行っていないと、それがどのように動作するかを周りの私の心をラップすることはできません。

私は約時間を探してきた、とカスタム検証を構築するためのソリューションのすべての種類を見てきましたが、MVC3控えめな検証を使用して、この特定の問題を解決するために何かを見つけることができません。

+0

これは、クライアント側の検証する必要もありませんか? –

+1

これが望ましいでしょう。私たちはこのサイトをMVC2からMVC3に変換しています。現在、MVC2の検証はクライアント側で行われていますので、そのまま使用していきたいと思います。しかし、可能であれば目立たない検証を使用したいと思います。現在の検証は非常に目障りです。 :) –

答えて

34

あなたは、この目的のためにカスタム検証属性を書くことができます:

public class DynamicRangeValidator : ValidationAttribute, IClientValidatable 
{ 
    private readonly string _minPropertyName; 
    private readonly string _maxPropertyName; 
    public DynamicRangeValidator(string minPropertyName, string maxPropertyName) 
    { 
     _minPropertyName = minPropertyName; 
     _maxPropertyName = maxPropertyName; 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     var minProperty = validationContext.ObjectType.GetProperty(_minPropertyName); 
     var maxProperty = validationContext.ObjectType.GetProperty(_maxPropertyName); 
     if (minProperty == null) 
     { 
      return new ValidationResult(string.Format("Unknown property {0}", _minPropertyName)); 
     } 
     if (maxProperty == null) 
     { 
      return new ValidationResult(string.Format("Unknown property {0}", _maxPropertyName)); 
     } 

     int minValue = (int)minProperty.GetValue(validationContext.ObjectInstance, null); 
     int maxValue = (int)maxProperty.GetValue(validationContext.ObjectInstance, null); 
     int currentValue = (int)value; 
     if (currentValue <= minValue || currentValue >= maxValue) 
     { 
      return new ValidationResult(
       string.Format(
        ErrorMessage, 
        minValue, 
        maxValue 
       ) 
      ); 
     } 

     return null; 
    } 

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     var rule = new ModelClientValidationRule 
     { 
      ValidationType = "dynamicrange", 
      ErrorMessage = this.ErrorMessage, 
     }; 
     rule.ValidationParameters["minvalueproperty"] = _minPropertyName; 
     rule.ValidationParameters["maxvalueproperty"] = _maxPropertyName; 
     yield return rule; 
    } 
} 

をして、それをあなたのビューモデルを飾る:

public class RangeValidationSampleModel 
{ 
    [DynamicRangeValidator("MinValue", "MaxValue", ErrorMessage = "Value must be between {0} and {1}")] 
    public int Value { get; set; } 
    public int MinValue { get; set; } 
    public int MaxValue { get; set; } 
} 

その後、ビューを提供するコントローラを持つことができます:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     return View(new RangeValidationSampleModel 
     { 
      Value = 5, 
      MinValue = 6, 
      MaxValue = 8 
     }); 
    } 

    [HttpPost] 
    public ActionResult Index(RangeValidationSampleModel model) 
    { 
     return View(model); 
    } 
} 

もちろん、表示:

@model RangeValidationSampleModel 

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script> 
<script type="text/javascript"> 
    $.validator.unobtrusive.adapters.add('dynamicrange', ['minvalueproperty', 'maxvalueproperty'], 
     function (options) { 
      options.rules['dynamicrange'] = options.params; 
      if (options.message != null) { 
       $.validator.messages.dynamicrange = options.message; 
      } 
     } 
    ); 

    $.validator.addMethod('dynamicrange', function (value, element, params) { 
     var minValue = parseInt($('input[name="' + params.minvalueproperty + '"]').val(), 10); 
     var maxValue = parseInt($('input[name="' + params.maxvalueproperty + '"]').val(), 10); 
     var currentValue = parseInt(value, 10); 
     if (isNaN(minValue) || isNaN(maxValue) || isNaN(currentValue) || minValue >= currentValue || currentValue >= maxValue) { 
      var message = $(element).attr('data-val-dynamicrange'); 
      $.validator.messages.dynamicrange = $.validator.format(message, minValue, maxValue); 
      return false; 
     } 
     return true; 
    }, ''); 
</script> 

@using (Html.BeginForm()) 
{ 
    <div> 
     @Html.LabelFor(x => x.Value) 
     @Html.EditorFor(x => x.Value) 
     @Html.ValidationMessageFor(x => x.Value) 
    </div> 
    <div> 
     @Html.LabelFor(x => x.MinValue) 
     @Html.EditorFor(x => x.MinValue) 
    </div> 
    <div> 
     @Html.LabelFor(x => x.MaxValue) 
     @Html.EditorFor(x => x.MaxValue) 
    </div> 
    <button type="submit">OK</button> 
} 

明らかにカスタムアダプターの登録はビューを汚染しないように外部のjavascriptファイルで実行する必要がありますが、私はこのポストの目的と簡潔さのためにビューに入れました。

+1

ダーリンありがとう、これは素晴らしいです!私はJavaScriptのコードに2つの小さな微調整をしなければならなかった。 'isNaN'チェックが逆転して('! 'を削除しなければなりませんでした)、メッセージが正しく設定されるように' isNaN'チェックで最小/最大チェックを移動しました。 –

+0

@JeradRose、確かに、私のコードに間違いがありました。私は今それを修正しました。問題がある場合は、私の回答を更新することを躊躇しないでください。 –

+0

ありがとう。私はそれを編集することを検討しましたが、まだそれを行う権限がありません(私はそれが2kだと思います)。 –

2

カスタム検証属性は確かに良い考えです。以下のようなもの(一部抜粋o'mineを掘りどこしばらく前に、誰もが知っている見つかっ):

public sealed class MustBeGreaterThan : ValidationAttribute 
{ 
    private const string _defaultErrorMessage = "'{0}' must be greater than '{1}'"; 
    private string _basePropertyName; 

    public MustBeGreaterThan(string basePropertyName) 
     : base(_defaultErrorMessage) 
    { 
     _basePropertyName = basePropertyName; 
    } 

    //Override default FormatErrorMessage Method 
    public override string FormatErrorMessage(string name) 
    { 
     return string.Format(_defaultErrorMessage, name, _basePropertyName); 
    } 

    //Override IsValid 
    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     var basePropertyInfo = validationContext.ObjectType.GetProperty(_basePropertyName); 
     var lowerBound = (int)basePropertyInfo.GetValue(validationContext.ObjectInstance, null); 
     var thisValue = (int)value; 

     if (thisValue < lowerBound) 
     { 
      var message = FormatErrorMessage(validationContext.DisplayName); 
      return new ValidationResult(message); 
     } 

     //value validated 
     return null; 
    } 
} 

public sealed class MustBeLowerThan : ValidationAttribute 
{ 
    private const string _defaultErrorMessage = "'{0}' must be lower than '{1}'"; 
    private string _basePropertyName; 

    public MustBeLowerThan(string basePropertyName) 
     : base(_defaultErrorMessage) 
    { 
     _basePropertyName = basePropertyName; 
    } 

    //Override default FormatErrorMessage Method 
    public override string FormatErrorMessage(string name) 
    { 
     return string.Format(_defaultErrorMessage, name, _basePropertyName); 
    } 

    //Override IsValid 
    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     var basePropertyInfo = validationContext.ObjectType.GetProperty(_basePropertyName); 
     var upperBound = (int)basePropertyInfo.GetValue(validationContext.ObjectInstance, null); 
     var thisValue = (int)value; 

     if (thisValue > upperBound) 
     { 
      var message = FormatErrorMessage(validationContext.DisplayName); 
      return new ValidationResult(message); 
     } 

     //value validated 
     return null; 
    } 
} 

その後、

public class RangeValidationSampleModel 
{ 
    [MustBeGreaterThan("MinValue")] 
    [MustBeLowerThan("MaxValue")] 
    int Value { get; set; } 

    int MinValue { get; set; } 

    int MaxValue { get; set; } 
} 

あなたのクラスを飾ると、あなたはあなた場合

+0

ありがとう@アレックス。これは、クライアント側の控えめな検証ではうまくいかないように見えますが、それは可能でしょうか? –

0

を行くために良いことがありますクライアントサイド検証が必要です。これはカスタムでなければなりません。私は最近、ここでの素敵なポストを見ました(ダーリンDmitrovそれを見つけるように見えるカント?)とにかく - これは、クライアント検証が発生することができます: http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx

サーバー側がIValidateableObjectかDynamic Range Validation in ASP.NET MVC 2

などなどに介して処理することができますサーバー側だけど、ここではクライアントサイドを鍵にしたいと思う。

関連する問題