ViewBagの場合、これは使用するべきだと聞いた。 ViewBagのコンテンツをビューモデルに組み込む必要があると思いますか?
質問:
私の仮定はベストプラクティスを超えています。 (ViewBagを使用せず、2番目にビューモデルに含めるため)
ViewBagが絶対に必要な状況はありますか?
ViewBagは動的辞書です。そのため、ViewBagを使用してアクションメソッドとビュー間でデータを転送する場合、ビュー内のViewBagアイテムにアクセスしようとするときにコードにタイプミスをすると、コンパイラはキャッチできません。ビューは実行時にクラッシュします:(
一般に、ビューモデルを使用して、アクションメソッドとビューの間でデータを転送することをお勧めします。ビューモデルは、ビューに固有のプロパティを持つ単純なPOCOクラスです。したがって、ビューに追加のデータを渡したい場合は、ビューモデルに新しいプロパティを追加し、それを使用します。強く型付けされたビューは、コードをよりクリーンで維持しやすくします。このアプローチを使用すると、ビューバッグに関係する一部のタイプにビューバッグ辞書項目を明示的にキャストする必要がなくなります。
public class ProductsForCategoryVm
{
public string CategoryName { set;get; }
public List<ProductVm> Products { set;get;}
}
public class ProductVm
{
public int Id {set;get;}
public string Name { set;get;}
}
アクションメソッドで、このビューモデルのオブジェクトを作成し、プロパティを読み込んでビューに送信します。
public ActionResult Category(int id)
{
var vm= new ProductsForCategoryVm();
vm.CategoryName = "Books";
vm.Products= new List<ProductVm> {
new ProductVm { Id=1, Name="The Pragmatic Programmer" },
new ProductVm { Id=2, Name="Clean Code" }
}
return View(vm);
}
そして、ビューモデルに強く型付けされたビューは、
@model ProductsForCategoryVm
<h2>@Model.CategoryName</h2>
@foreach(var item in Model.Products)
{
<p>@item.Name</p>
}
多くのチュートリアル/ブックには、ドロップダウンデータにViewBagを使用するコードサンプルがあります。個人的には、これにはViewBagを使用すべきではないと考えています。ドロップダウンデータを渡すには、ビューモデルのList<SelectListItem
>型のプロパティである必要があります。 post とその方法のコード例を示します。
ViewBagが絶対に必要な状況はありますか?
ViewBagを使用してデータを送信できる(不要)の有効な使用例がいくつかあります。たとえば、レイアウトページに何かを表示したい場合は、ViewBagを使用できます。別の例は、デフォルトのMVCテンプレートに存在するViewBag.Title
(ページタイトル)です。
public ActionResult Create()
{
ViewBag.AnnouncementForEditors="Be careful";
return View();
}
レイアウトでは、ViewBag.AnnouncementForEditors
を読むことができます
<body>
<h1>@ViewBag.AnnouncementForEditors</h1>
<div class="container body-content">
@RenderBody()
</div>
</body>
1)ベストプラクティスよりも上の私の仮定です。 (ViewBagを使用せず、2番目にビューモデルに含めるため)
可能な限りViewBagを介してデータを渡すのではなく、ビューモデルを使用する必要があります。
2)ViewBagが絶対に必要な状況はありますか?
ViewBagが絶対に必要な状況はありません。ただし、個人的にView Modelの代わりにViewBagを使用することを好むデータがいくつかあります。たとえば、定義済みの値(つまり都市)のドロップダウンボックスにデータを入力する必要がある場合、SelectListItem配列を表示するためにViewBagを使用します。このデータでViewModelを汚染しないことを好みます。
1)ベストプラクティスよりも上の私の仮定です。 (ViewBagを使用せず、2番目にビューモデルに含めるため)
はい。
2)ViewBagが絶対に必要な状況はありますか?
いいえ。ViewBagに保存したものはすべて、ビューに渡されるビューモデルに入ることができます。
ViewBagsの問題と推奨されるベストプラクティスは、コンパイル時のチェックに要約されます。 ViewBagは単なる辞書であり、「魔法の」文字列を取得するため、<MvcBuildViews>true</MvcBuildViews>
を使用してビューをプリコンパイルしても、ビューバッグアイテムの1つのオブジェクトタイプまたはキー名を変更してしまうと、実行時までわかりません。
特定のビューに合わせてモデルを変更する必要がある場合でも、ビューモデルに固執するのが最適です。
すべてのページに共通の機能があり、表示されるページに依存しない機能があるViewBagの使用法をいくつか見つけました。たとえば、StackOverflowを構築しているとします。ジョブボードは各ページに表示されますが、表示されているジョブはページとは何の関係もありません(私の使い方は概念的には似ていました)。各ViewModelにプロパティを追加するのは難しく、時間がかかり、テストにlotが必要です。この状況では価値があるとは思いません。
私はクロスカッティングデータでベースのViewModelクラスを使用しましたが、複数の場合(たとえば、ジョブとスタック交換サイトのリスト)、余分なデータの詰め込みを開始するか、ViewModelのその他の乱用に加えて、基本データを取り込むためにViewModelビルダーが必要です。
マジックストリングの問題に関しては、多くの解決策があります。定数、拡張メソッドなど.
とは言っても、ページのコンテキストに依存するページに表示されるものがある場合、ViewModelはあなたの友人です。
エリック
既存のViewModelを再設計できない場合は、ViewBagを使用してください。
2.ViewBagが絶対に必要な状況はありますか?
場合によっては、コントローラーのデータをレイアウト、ビュー、および部分ビューで共有する必要があります。この場合、ViewBagは非常に有用であり、より良い方法があるとは思いません。
ViewBagを広範囲に使用しているので、これについて意見を述べると思いました。
それを使用することで得られる唯一の本当の利点は、小さなプロジェクトの場合、または新しいプロジェクトがあり、ボールを転がしたいだけで、モデルクラスのロードの作成を心配する必要がない場合です。
プロジェクトがより成熟すると、アプリケーション全体で弱いタイピングを使用することに起因する予期しない動作の問題が見つかる場合があります。ロジックは混乱を招き、テストが難しく、問題が発生した場合のトラブルシューティングが困難になる可能性があります。
実際にViewBagをアプリケーションから完全に削除し、他の開発者が同じコードベース内でそれを使用するときにコンパイルエラーをスローすることを防止するルートをたどりました。 Razorビュー内でも試してみてください。
以下は、GitHub上のASP.NET 5プロジェクトのサンプルです。ここでは削除しました: https://github.com/davidomid/Mvc5NoViewBag
そして、これを削除する動機とソリューションがどのように機能するかについて説明するブログ投稿があります: https://www.davidomid.com/hate-the-aspnet-mvc-viewbag-as-much- as-i-do-heres-how-to-remove-it
ユースケースがない場合、そもそも実装されません。はい、ViewModelsを使用してすべてを実行できますが、本当に必要ない場合はどうでしょうか。そのようなシナリオの1つは、エンティティの編集です。 DTOをモデルとして直接渡すことができます。
@model CategoryDto
<div class="md-form form-sm">
<input asp-for="Name" class="form-control">
<label asp-for="Name">("Category Name")</label>
</div>
しかし、カテゴリの親を選択する場合はどうでしょうか?エンティティDTOは、理想的には自身の値のみを保持するため、選択リストに入力するにはViewBagを使用します
<select asp-for="ParentId" asp-items="ViewBag.ParentList">
<option value="">None</option>
</select>
どうしてですか?それぞれ50種類のエンティティがあり、それぞれ異なる値から何らかの選択がある場合、50の余分なViewModelを作成することは避けました。