これはかなり一般的な SO の質問です。
最初の質問は、通常はフォーム B の方が優れていることに同意しますか?
フォーム Bを使用しないのは、ファイルをアップロードするときだけです。そうでなければ、誰もForm Aを使用する必要はないと思います。人々がフォーム Aを使用する理由は、MVC の ASP.Net バージョンの機能を理解していないためだと思います。
第 2 に、フォーム B を使用する場合、デコレータ タイプの検証を ViewModel に含める必要があるようです。
並べ替え/依存します。例を挙げます:
public IValidateUserName
{
[Required]
string UserName { get; set; }
}
public UserModel
{
string UserName { get; set; }
}
[MetadataType(typeof(IValidateUserName))]
public UserValiationModel : UserModel
{
}
検証デコレーターはインターフェースにあります。派生クラスで MetadataType を使用して、派生型を検証しています。再利用可能な検証が可能で、MetadataType/Validation は ASP.NET コア機能の一部ではないため、ASP.Net (MVC) アプリケーションの外部で使用できるため、私は個人的にこの方法が気に入っています。
ViewModels にエンティティを埋め込む利点はありますか..
はい、基本的なモデルをビューに渡さないように最善を尽くしています。これは私がしないことの例です:
public class person { public Color FavoriteColor { get; set; } }
ActionResult Details()
{
Person model = new Person();
return this.View(model);
}
ビューにさらにデータを渡したい場合 (パーシャル データまたはレイアウト データ) はどうなりますか? ほとんどの場合、その情報は Person 関連ではないため、 Person モデルに追加しても意味がありません。代わりに、私のモデルは通常次のようになります。
public class DetailsPersonViewModel()
{
public Person Person { get; set; }
}
public ActionResult Details()
{
DetailsPersonViewModel model = new DetailsPersonViewModel();
model.Person = new Person();
return this.View(model);
}
DetailsPersonViewModel
これで、Person が知っている以上にそのビューが必要とする必要なデータを追加できます。たとえば、Person がお気に入りを選択するためのすべての色を含む for を表示するとします。可能なすべての色は人物の一部ではなく、人物モデルの一部であってはならないため、それらを DetailPersonViewModel に追加します。
public class DetailsPersonViewModel()
{
public Person Person { get; set; }
public IEnumerable<Color> Colors { get; set; }
}
..エンティティレベルのみで検証を維持しますか?
System.ComponentModel.DataAnnotations
プロパティのプロパティを検証するように設計されていないため、次のようにします。
public class DetailsPersonViewModel()
{
[Required(property="FavoriteColor")]
public Person Person { get; set; }
}
存在しませんし、意味がありません。検証が必要なエンティティの検証を ViewModel に含める必要がない理由。
デフォルトのコンストラクターがなく、最初のアプローチを使用する必要がある場合、この編集アクションは失敗します。
正解ですが、ViewModel または ViewModel 内のエンティティにパラメーターなしのコンストラクターがないのはなぜですか? 悪い設計のように聞こえますが、これに何らかの要件がある場合でも、ModelBinding によって簡単に解決できます。次に例を示します。
// Lets say that this person class requires
// a Guid for a constructor for some reason
public class Person
{
public Person(Guid id){ }
public FirstName { get; set; }
}
public class PersonEditViewModel
{
public Person Person { get; set; }
}
public ActionResult Edit()
{
PersonEditViewModel model = new PersonEditViewModel();
model.Person = new Person(guidFromSomeWhere);
return this.View(PersonEditViewModel);
}
//View
@Html.EditFor(m => m.Person.FirstName)
//Generated Html
<input type="Text" name="Person.FirstName" />
これで、ユーザーが新しい名前を入力できるフォームができました。このコンストラクターで値を取得するにはどうすればよいでしょうか? シンプルです。ModelBinder はバインド先のモデルを気にせず、HTTP 値を一致するクラス プロパティにバインドするだけです。
[MetadataType(typeof(IPersonValidation))]
public class UpdatePerson
{
public FirstName { get; set; }
}
public class PersonUpdateViewModel
{
public UpdatePerson Person { get; set; }
}
[HttpPost]
public ActionResult Edit(PersonUpdateViewModel model)
{
// the model contains a .Person with a .FirstName of the input Text box
// the ModelBinder is simply populating the parameter with the values
// pass via Query, Forms, etc
// Validate Model
// AutoMap it or or whatever
// return a view
}