2009-07-16 21 views
19

ASP.NET MVCで検証を実装する方法のヒントのほとんどは、モデル(モデルとコントローラの間のサービスレイヤを構築するか、検証属性を使用してモデルのプロパティを修飾する)を中心にしているようです。ASP.NET MVCのViewModelsの検証

私のアプリケーションでは、コントローラとビュー間のすべての通信にViewModelsを使用します。

「EmailAddress」というプロパティを持つ「LoginViewModel」というログインページ用のViewModelがあります。

ユーザーが電子メールアドレスを入力して送信をクリックすると、このViewModelが入力され、コントローラに送信されます。コントローラでは、電子メールアドレスが検証されます。

有効なメールアドレスで、ユーザーはシステムに登録されているドメインのユーザーである必要があります。

これにバリデーションを追加する便利な方法はありますか?私はViewModel自体に検証を入れるべきですか?それともコントローラーに残っていますか?

答えて

5

「検証をViewModel自体に入れる必要がありますか?またはコントローラに残すべきですか?私はRobertに同意しますが、追加の自動化のためのプラグを追加します。xValのようなツールを見ると、範囲、正規表現に一致する文字列)は、データクラスのフィールドを修飾して自動的に行うことができます(実際には、xValはルーチン検証用のJavaScriptを自動的に作成してクライアント側で実行されます)。このユーザーは私たちのデータベースに登録されているドメインのメンバですか?)モデルのレイヤー内でサーバー側で発生します

ViewModelイディオムを使用すると、このスキームにいくつかの問題が生じる可能性があります。ビューモデル内に

public class Contact { 
    [Required] 
    string Name { get; set; } 
} 

public class ContactView { 
    public Contact Contact { get; set; } 
    public string SomeOtherViewProperty { get; set; } 
} 

及びモデルを更新するとき、コントローラは、浅い検証が起こる:詳細またはより複雑な計算を必要と

UpdateModel(contactViewModel.Contact, "Contact"); 

および検証は、モデル層自体の内部で起こります。

もう1つのアプローチは、エンティティオブジェクトを埋め込むのではなく、2つのオブジェクトの間に個々のフィールドをマップすることです。私は最近ドメインとビューモデルオブジェクトの間でフィールドを自動的にリンクするAutoMapperというツールを認識しました。私はまだそれを使用していませんが、この検証方法をサポートする必要がありますように見えます。

+0

素晴らしいアイデア、Keith!現時点では、ViewModelsにモデルを埋め込むのと同じ戦略があります。 ModelとViewModelの両方で同じ方法で検証を実装でき、xValなどのJSフレームワークがどちらかとシームレスに連携できる場合はどうすればいいですか。 これは最も柔軟な方法です。私は検証がモデルに専ら結びついているとは思わない。 – Jonathan

+0

私はまた、xValを含む組み込みモデルクラスを持つカスタムビューモデルを使用しています。しかし、モデルのプロパティのサブセットのみを含むビューモデルが必要な場合があります。私は現在、これらのモデルをマップするAutomapperを探しています。それは正常に動作しますが、私はそのシナリオでxValを使用する方法は?メタモデルオブジェクトにviewmodelの一部ではないプロパティが含まれる場合、AssociatedMetadataTypeTypeDescriptionProviderがスローするため、ViewModelをMetaData属性でデコレートすることはできません。 Automapperを使用している場合は、この問題の解決方法を知りたいと思います。 –

3

NerdDinner tutorialsは、モデルの部分クラス(つまり、LinqからSQLまたはEntity Framework)での検証が行われていることを示しています。しかし、View Modelを使用しているので、そこに検証ロジックを置くことができます。

検証ロジックはコントローラにはありません。むしろ、それはチェックのプロパティを持つコントローラ、すなわちModelState.IsValidから引っ掛けて

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Create(Dinner dinner) { 

    if (ModelState.IsValid) { 

     try { 
      dinner.HostedBy = "SomeUser"; 

      dinnerRepository.Add(dinner); 
      dinnerRepository.Save(); 

      return RedirectToAction("Details", new { id=dinner.DinnerID }); 
     } 
     catch { 
      ModelState.AddModelErrors(dinner.GetRuleViolations()); 
     } 
    } 

    return View(new DinnerFormViewModel(dinner)); 
} 

完全な詳細はここにある:こちらのモデル
http://nerddinnerbook.s3.amazonaws.com/Part3.htm

や建物

ViewDataおよびViewModel
http://nerddinnerbook.s3.amazonaws.com/Part6.htm

+0

** **アップデートされたNerdDinnerについては、こちらをご覧ください:http://nerddinner.codeplex.com/SourceControl/changeset/view/ef63780655b0 –