2011-07-01 5 views
5

asp.net mvcの一般的な推奨事例の1つはyou should not send your business models to your viewsです。代わりに、各ビューに固有のビューモデルを作成する必要があります。ここであなたの検証をasp.net mvc 3に入れますか?

これが完了し、コントローラでModelState.IsValidメソッドを呼び出すと、ビジネスモデルではなくビューモデルの有効性が効果的にチェックされます。

これに対処する従来のアプローチは何ですか?

public class Person 
{ 
public int ID {get; set;}; 

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

[Required] 
public string LastName {get; set;} 

public virtual ICollection<Exam> Exams {get; set;} 

} 

public class PersonFormViewModel 
{ 

public int ID {get; set;};  


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

[Required] 
public string LastName {get; set;} 

} 

これは、[必須]属性は、両方のモデルまたはちょうどViewModelにあるいは単にビジネスモデルに表示されますかどうかわからない、私は今持っている正確に何ですが、イム。

この問題に関するヒントは高く評価されています。

ビューモデルを常に使用するのが一般的な良い方法であるという私の主張を支持するためのリンクがさらにあります。

How to add validation to my POCO(template) classes

http://blogs.msdn.com/b/simonince/archive/2010/01/26/view-models-in-asp-net-mvc.aspx

+0

「ビジネスモデル」は何ですか? –

+0

PersonはEntityFrameworkによって追跡されるクラスです。 PersonViewModelは明らかに私がリンクしているブログの記事を読んでいないので、あなたが従うべきことを理解しようとしています。したがって、検証ロジックはどこに行くべきかという疑問です。 – ignaciofuentes

+0

ありがとう - 申し訳ありませんが、記事をスキャンし、その中で "ビジネスモデル"を検索しましたが、ヒットしませんでした。 –

答えて

7

私の好みは、ビューモデル上入力の検証、およびドメインモデルビジネス検証を行うことです。

つまり、必須フィールド、長さ検証、正規表現などのデータアノテーションは、ビューモデルで実行し、エラーが発生した場合はモデル状態に追加する必要があります。

あなたはおそらく単なる「フォーム」以上のものに依存するビジネス/ドメインのルールを持っているでしょうから、ドメインモデルでそれを行う(それらがマップされた後に検証を実行する)か、サービス層。

すべてのモデルには、「検証」と呼ばれるメソッドがあり、永続化する前にサービスで呼び出します。ビジネス検証に失敗した場合、カスタム例外がスローされます。ビジネス検証は、コントローラによって捕捉され、モデル状態に追加されます。

誰もが紅茶ではないかもしれませんが、一貫しています。

ビジネス検証の例は、要求通り:

public abstract class Post 
{ 
    // .. fields, properties, domain logic, etc 

    public void Validate() 
    { 
     if (!this.GeospatialIdentity.IsValidForThisTypeOfPost()) 
     throw new DomainException(this, BusinessException.PostNotValidForThisSpatial.); 
    } 
} 
:ここ

は、一般的な「ポスト」(質問、写真、動画など)を表し、我々が持っているドメインモデルの例です

私はビジネスルールをチェックしており、カスタム例外を投げています。 DomainExceptionが私たちの拠点であり、多くの派生的な実装があります。 BusinessExceptionと呼ばれる列挙型がありますが、これにはすべての例外の値が含まれています。列挙型の拡張メソッドを使用して、リソースベースのエラーメッセージを提供します。

これは単純にモデルのチェックのフィールドではありません。たとえば、「すべての投稿には件名が必要です」ということです。これはドメインの一部ですが、まず入力の検証が行われるため、データ注釈ビューモデル上で今

、コントローラ:

[HttpPost] 
public ActionResult Create(QuestionViewModel viewModel) 
{ 
    if (!ModelState.IsValid) 
    return View(viewModel); 

    try 
    { 
     // Map to ViewModel 
     var model = Mapper.Map<QuestionViewModel,Question>(viewModel); 

     // Save. 
     postService.Save(model); // generic Save method, constraint: "where TPost: Post, new()". 

     // Commit. 
     unitOfWork.Commit(); 

     // P-R-G 
     return RedirectToAction("Index", new { id = model.PostId }); 
    } 
    catch (Exception exc) 
    { 
     var typedExc = exc as DomainException; 

     if (typedExc != null) 
     { 
     // Internationalised, user-friendly domain exception, so we can show 
     ModelState.AddModelError("Error", typedExc.BusinessError.ToDescription()); 
     } 
     else 
     { 
     // Could be anything, e.g database exception - so show generic msg. 
     ModelState.AddModelError("Error", "Sorry, an error occured saving the Post. Support has been notified. Please try again later."); 
     } 
    } 

    return View(viewModel); 
} 

だから、我々はサービスの「保存」の方法を取得時までに、モデルが経過した入力の検証。次に、Saveメソッドはビジネス・ルールを呼び出すpost.Validate()を呼び出します。

例外が発生した場合、コントローラはそれをキャッチしてメッセージを表示します。それがSaveメソッドをパスし、別のエラーが発生すると(例えば、90%の時間、Entity Frameworkなど)、一般的なエラーメッセージが表示されます。

私が言ったように、皆にとってではないが、これは私たちのチームにとってはうまくいく。私たちは、プレゼンテーションとドメインの検証を明確に分離しており、生のHTTP POSTから成功後のリダイレクトへの一貫した制御フローを持っています。

HTH

+0

これの小さな例を投稿してもよろしいですか?特にコントローラメソッドです。 – ignaciofuentes

+2

@NachoF - あなたが望むように、例が追加されました。 – RPM1984

0

一般的に、あなたのViewModelには、あなたのモデルへの参照が含まれています - あなたがあなたのモデルでは使用できません、あなたのビューに追加情報を表示する必要がある場合のViewModelにのみ必要であり、そこに既に存在するデータを複製する必要はありません。

+0

あなたが言っていることは、ビジネスオブジェクト自体に含まれていない追加の情報が必要ないときに、ビジネスモデルオブジェクトをビューに渡すことです。 – ignaciofuentes

+0

正しい例、ここhttp://weblogs.asp.net/scottgu/archive/2010/01/15/asp-net-mvc-2-model-validation.aspx Scott Guthrieは、データアノテーションを含むPersonタイプをコントローラーでの彼の見解。 – devdigital

+0

私はちょうどあなたがリンクしている記事を読んだことがあります。ジミーが「自分のビジネスモデルをあなたのビューに送ってはいけない」と言われている場所はどこにもありません。事実、「not」という言葉は記事のどこにも現れておらず、Jimmyは「もちろん、これらの意見の多くはプロジェクトの制約の中で本当に有効である」、「これらの意見はあなたに当てはまるかもしれません。上で働く。 – devdigital

4

MetaDataの「バディ」クラスは、まさにこのためのクラスです。検証は、一度作成されますが、モデルとのviewmodel両方のクラスで使用することができます:あなたは常にあなたのビューにのviewmodelsを渡し、自分のドメインモデルは、Iドンその後、ビューを通じてエンドユーザーに公開されていないことを考えると

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

    [Required] 
    public string LastName {get; set;} 
} 

[MetadataType(typeof(PersonMetaData))] 
public class Person 
{ 
    public string Name {get; set;} 
    public string LastName {get; set;} 
} 

[MetadataType(typeof(PersonMetaData))] 
public class PersonFormViewModel 
{ 
    public string Name {get; set;} 
    public string LastName {get; set;} 
} 
+0

ビジネスクラス全体をビューに渡し、ViewModelとして編集可能なデータを生成してコントローラに戻し、それをORM x 1000ビューに渡す際のperforamnceの意味は何ですか?具体的なViewModelそのモデルをビジネスに表示して渡し、正しいデータに変換します。データは常にビジー状態ですが、バディークラスはviewEngineのビジー状態のサーバーのオーバーヘッドにどのように影響しますか?確かに簡単ですが、サーバーを悩ませることも簡単です。なぜなら、これらのアクションの意味を理解していないからです。 – ppumkin

1

ドメインモデルそのものを検証する必要はありません。たとえば、フォームからフォームへのビューからPersonViewModelを受け取った場合、PersonViewModelが有効な場合にのみ、それをPerson Model(おそらくオートマッパーなど)に変換します。だから私は入力検証は、入力にバインドされているので、ビューモデルにとどまるべきだと考えています。

2

RPM1984グレート答え、そして素敵なコードサンプル。

私は、最初からバリアント2を使用しているのは、生産性と構造の間の実用的なバランスですが、場合によってはバリアント3に移行する必要がありますので、2つのアプローチの組み合わせを提唱します。論理的。パターン&ただし、バリアント3は、理想的な分離などの理由から常に推奨されています。同じソリューションで2つのアプローチを使用しないでください。一部の人は好きではありません。すべてのモデルに対して。

私は、ビューモデル内のビジネスエンティティを再利用することは、検証を再利用するのに便利だが、しばしばビジネスロジックが別の検証も行う必要があることを心に留めておくこと(RPM1984のチェックレコードはまだ存在していません)。バリアント3を使用すると、ビューのニーズに合わせてビューモデルの検証を集中することができます(わずかな労力を犠牲にして)。しかし、ビジネスロジックの検証も必要になります。

+0

あなたは答えるのではなくコメントを使うことを考えなければなりません。 –

関連する問題