web-dev-qa-db-ja.com

ASP.NET MVC-ビューモデルの正確な使用方法

ユーザーの詳細を編集できるページがあるとします。したがって、次のようなViewModelがあります。

public class UserViewModel {
    public string Username { get; set; }
    public string Password { get; set; }
    public int ManagerId { get; set; }
    public string Category { get; set; }
}

そのため、EditUserアクションで、これをモデルバインダーから返すことができ、それをドメインモデルにマッピングできます。

public ActionResult EditUser(UserViewModel user) {
    ...

ただし、フォームを表示するページには、これらのフィールドにドロップダウンを提供するためのマネージャーおよびカテゴリーのリストなどの詳細も必要です。また、他のユーザーのリストをサイドバーに表示して、編集中のさまざまなユーザーを切り替えることもできます。

したがって、別のビューモデルがあります。

public class ViewUserViewModel {
    public UserViewModel EditingUser { get; set; }
    public IEnumerable<SelectListItem> Managers { get; set; }
    public IEnumerable<SelectListItem> Categories { get; set; }
    public IEnumerable<SelectListItem> AllUsers { get; set; }
}

これは正しい方法ですか?両方ともビューモデルですか?その場合、モデルのようなVMとページのデータのみを含むVMを区別できるように、使用すべき命名規則がありますか?

私はこれをすべて間違っていますか?

36
littlecharva

ショートカットでこれを行う方法:

  1. ページ上のフォームごとに個別のViewModelクラスを作成し、PartialViewsでこれらのクラスを@{Html.RenderPartial("PartialName", Model.PartialModel);}としてレンダリングします。
  2. ページにhtmlメタなどが含まれている場合、メタ用に分離したクラスを作成し、ページのセクションに配置します。
  3. 「これを別のクラスに入れるべきですか?」あなたの判断です。

そのため、たとえば、何らかの種類のログイン/登録バーまたはポップアップを含むページがあります。

public class SomePageViewModel
{
    public RegisterBarVM Register { get; set; }
    public LoginBarVM LoginBar { get; set; }

    public MetasVM Metas { get; set; }
    public string MaybePageTitle { get; set;}
    public string MaybePageContent { get; set;}

    [HiddenInput(DisplayValue = false)]
    public int IdIfNeeded { get; set; }

    public IEnumerable<SelectListItem> SomeItems {get; set;}
    public string PickedItemId { get;set; }
}

public class RegisterBarVM
{
    public string RegisterUsername {get;set;}
    public string RegisterPassword {get;set;}
    //...
}

public class LoginBarVM
{
    public string LoginUserame {get;set;}
    public string LoginPassword {get;set;}
    //...
}

//cshtml
@model yourClassesNamespace.SomePageViewModel
@{
    Html.RenderPartial("LoginBar", Model.LoginBar); //form inside
    Html.RenderPartial("RegisterBar", Model.RegisterBar); //form inside

    using(Html.BeginForm())
    {
        @Html.EditorFor(m => m.IdIfNeeded)
        @Hmtl.EditorFor(m => m.MaybePageTitle)
        @Hmtl.EditorFor(m => m.MaybePageContent)

        @Hmtl.DropDownListFor(m => m.PickedItemId, new SelectList(Model.SomeItems))

        <input type="submit" value="Update" />
    }
}

@section Metas {
    @{Html.RenderPartial("Meatas", Model.Metas}
}

エディターテンプレートについて Brad Wilsons Blog で、Googleを使用するか、ディスプレイ/エディターテンプレートとHtmlHelpersに関するスタックリソースを探します。これらはすべて、一貫したWebサイトの構築に非常に役立ちます。

20
Mariusz

「モデルの表示」は単なるパターンです。名前について魔法のようなことは何もありませんが、通常、ビューに渡されるクラス(単純にデータを表示するため、またはフォーム送信の目的のために)は、「ビューモデル」と呼ばれ、FooViewModelのような名前が付けられますまたはFooVMは、それがその「ビューモデル」パターンの一部であることを示します。

哲学的になりすぎたくはありませんが、遊びのパターンについて少し言及しておくと役立つと思います。 ASP.NET MVCは明らかにMVC(Model-View-Controller)アーキテクチャモデルを推奨しています。 MVCでは、モデルはすべてのアプリケーションのビジネスロジックのコンテナです。コントローラーは、リクエストの処理、モデルの取得、そのモデルでのビューのレンダリング、および応答の返送を担当します。それは多くの責任のように思えますが、実際にはフレームワークはこれのほとんどを舞台裏で処理します。そのため、コントローラーは通常、コードが非常に軽いです(そうすべきです)。彼らはすべてを結びつけるための最低限の機能を担います。最後に、ビューは、ユーザーがモデル内のデータを操作できるようにするUIレイヤーを作成します。 notデータ自体に責任を負わず、責任も負わない(ここで、ViewData/ViewBagは、少なくとも実際には開発者が使用する方法と同じくらい、かなり大きな違反です)。

したがって、アプリケーションロジックの大部分はモデル内にある必要があり、通常はそれが良いことです。ただし、モデルはアプリケーションデータの避難所であるため、通常はデータベースなどに永続化されます。永続化すべきデータと、表示目的でのみ存在すべきデータとの間でバランスをとる必要があるため、利益相反が生じます。

これがビューモデルの出番です。MVC(Model-View-View Model)は、MVCとやや平行したパターンであり、1つのモデルからすべてのルールに至るアプローチの固有の問題を認識します。 MVCはこのパターンを使用しないため、ここでは詳しく説明しません。ただし、ほとんどのASP.NET MVC開発者は、MVVMのビューモデルを採用しています。本質的には、データベースを利用したエンティティ(従来のモデル)であり、通常はさまざまな状態のエンティティを表す多くの異なるビューモデルです。これにより、モデルに永続性に関連するビジネスロジックを含めることができ、ビューモデルにはそのモデルの表示、作成、更新に関連するビジネスロジックが含まれます。

私は少し軌道に乗りましたが、長短は、あなたがやっていることは完全に受け入れられるということです。実際、それは良い習慣です。アプリケーションに必要な数のビューモデルを作成し、それらを使用して、ビューに必要なデータとビジネスロジックを実際に保存します。 (これにはSelectListsなどが含まれます。コントローラーもビューも、ドロップダウン用にSelectListを作成する方法を知る必要はありません。)

94
Chris Pratt

私は個人的に、ViewModelの目的であるViewにすべてのデータを提供するために、ViewModelにページをレンダリングするために必要なすべての情報を配置することを好みます。したがって、私のUserViewModelにはManagersCategoriesおよびAllUsersのプロパティが含まれ、ViewModelをビューに渡す前にコントローラーがこれらのコレクションを埋めます。

これは基本的にあなたがしたことです-方程式から余分なViewModelを削除するだけです。

また、他のプログラマがViewDataを使用してドロップダウンリストをビューに送信することも確認しましたが、ViewModelはそうではありませんが、ViewDataは強く型付けされていないため、これは嫌です。

9
Jason Berkan