2011-06-21 15 views
28

MVAがModelAnnotation属性(必須または範囲など)を最初に実行し、それらのいずれかが失敗した場合、IValidatableObjectモデルでValidateメソッドをスキップしてモデルを検証すると思われます。MVCにIValidatableObjectの検証を強制する方法

MVCは先に行くと、他の検証が失敗した場合でも、その方法を実行させる方法はありますか?

+0

正に、私はこのデフォルトの動作が気に入っています。データベース接続のような高価なものが含まれるValidateメソッドでビジネスレベルの検証を行う場合、モデルが有効でない限り呼び出さないほうがよいです。 – Graham

答えて

32
手動そうように、ValidationContextの新しいインスタンスに渡すことによって検証()を呼び出すことができ

[HttpPost] 
public ActionResult Create(Model model) { 
    if (!ModelState.IsValid) { 
     var errors = model.Validate(new ValidationContext(model, null, null)); 
     foreach (var error in errors)         
      foreach (var memberName in error.MemberNames) 
       ModelState.AddModelError(memberName, error.ErrorMessage); 

     return View(post); 
    } 
} 

このアプローチの注意点は、その(DataAnnotation)エラーなし性レベルが存在しない場合において検証は2回実行されます。それを避けるために、あなたはあなたのモデルにプロパティを追加することができ、それが実行され、その後、手動でコントローラにメソッドを呼び出す前に確認したら、あなたのvalidate()メソッドでtrueに設定ブール検証済みの、と言います。だからあなたのコントローラで

if (!ModelState.IsValid) { 
    if (!model.Validated) { 
     var validationResults = model.Validate(new ValidationContext(model, null, null)); 
     foreach (var error in validationResults) 
      foreach (var memberName in error.MemberNames) 
       ModelState.AddModelError(memberName, error.ErrorMessage); 
    } 

    return View(post); 
} 

そして、あなたのモデルでは:

public bool Validated { get; set; } 

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { 
    // perform validation 

    Validated = true; 
} 
+0

ありがとうございました。しかし、私は1つの質問を得ました.Ivalidate Objectが発砲しているので何らかの理由がありますか?いつかそれはできないかもしれない? – user998405

26

各コントローラのアクションの先頭に定型的なコードを必要とせずにそれを行うための方法があります。

あなたがあなた自身のものとデフォルトのモデルバインダーを交換する必要があります

protected void Application_Start() 
{ 
    // ... 
    ModelBinderProviders.BinderProviders.Clear(); 
    ModelBinderProviders.BinderProviders.Add(new CustomModelBinderProvider()); 
    // ... 
} 

あなたのモデルバインダープロバイダーは、次のようになります。

public class CustomModelBinderProvider : IModelBinderProvider 
{ 
    public IModelBinder GetBinder(Type modelType) 
    { 
     return new CustomModelBinder(); 
    } 
} 

さて、実際にカスタムモデルバインダーを作成します検証を強制する。ここで重労働が行われます:

また、IndexOf拡張メソッドも必要です。これは安価な実装ですが、動作します:

public static int IndexOf<T>(this IEnumerable<T> source, Func<T, bool> predicate) 
{ 
    if (source == null) throw new ArgumentNullException("source"); 
    if (predicate == null) throw new ArgumentNullException("predicate"); 

    var i = 0; 
    foreach (var item in source) 
    { 
     if (predicate(item)) return i; 
     i++; 
    } 

    return -1; 
} 
+0

ありがとう、これは私を助けてくれました。 – Haney

+0

このソリューションはDefaultModelBinderでのみ動作すると思います – HamedH

関連する問題