关于 ViewBag,我听说使用它是不好的。我认为应该将 ViewBag 中的内容合并到视图模型中,是最佳实践?
问题:
我的假设是最佳实践吗?(不使用 ViewBag,其次将其内容放入视图模型中)
是否有绝对需要使用 ViewBag 的情况?
关于 ViewBag,我听说使用它是不好的。我认为应该将 ViewBag 中的内容合并到视图模型中,是最佳实践?
问题:
我的假设是最佳实践吗?(不使用 ViewBag,其次将其内容放入视图模型中)
是否有绝对需要使用 ViewBag 的情况?
1) 我的假设是否符合最佳实践。(不使用ViewBag,而是将其放在视图模型中)
尽可能使用视图模型代替通过ViewBag传递数据。
2) 是否存在必须使用ViewBag的情况?
没有必须使用ViewBag的情况。但是,某些数据我个人更喜欢使用ViewBag而不是视图模型。例如,当我需要为预定义值(如城市)填充下拉框时,我使用ViewBag来传递SelectListItem数组到视图中。我不想用这些数据来污染我的视图模型。
ViewBag是一个动态字典。因此,当使用ViewBag在操作方法和视图之间传递数据时,你的编译器无法捕获如果有代码中拼写错误尝试访问ViewBag项的情况。你的视图将在运行时崩溃 :(
通常最好使用视图模型在操作方法和视图之间传递数据。视图模型是一个简单的POCO类,具有特定于视图的属性。因此,如果要向视图传递一些附加数据,请将新属性添加到视图模型中并使用它。强类型视图使代码更干净、更易于维护。通过这种方法,你不需要对你的ViewBag字典项进行显式转换来回多次,这是你必须使用ViewBag时要做的。
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 来传递下拉菜单数据。我个人认为不应该这样做,而是应在视图模型中将其定义为类型为 List<SelectListItem>
的属性来传递下拉菜单数据。在这里有一个帖子,其中提供了如何实现的示例代码。
是否存在绝对必须使用 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 的情况?
没有。您在 ViewBag 中存储的所有内容都可以放入传递给视图的视图模型中。
<MvcBuildViews>true</MvcBuildViews>
预编译视图也无济于事。我想发表我的观点,因为我经常使用ViewBag。
你只有在小项目中使用它,或者在你有一个新项目而且只是想开始运行而不必担心创建大量模型类的情况下才会从中获得真正的好处。
当你的项目更加成熟时,您可能会发现由于在整个应用程序中使用弱类型而导致的意外行为问题。逻辑可能令人困惑,难以测试,并且当事情出错时难以进行故障排除。
实际上,我曾经从我的应用程序完全删除了ViewBag,并通过在Razor视图中尝试使用ViewBag时引发编译错误来防止其他开发人员在同一代码库中使用它。
这里是一个ASP.NET 5项目的示例,我已经从中删除了ViewBag:https://github.com/davidomid/Mvc5NoViewBag
以下是一篇博客文章,我在其中解释了移除它的动机以及解决方案的说明: https://www.davidomid.com/hate-the-aspnet-mvc-viewbag-as-much-as-i-do-heres-how-to-remove-it
@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>
冒着重新引发争议的风险,让我提供一点见解。无论什么是“最佳实践”,让我提供现实世界的经验,广泛使用ViewBag可能成为一个令人头痛的问题源,难以找到的错误和问题会让人非常困扰,而且很难追踪和解决。即使可以建立关于使用ViewBag的可接受概念或规则,它们也很容易成为初级开发人员依赖分心的支撑,并阻碍正确、强类型的ViewModels的开发。
不幸的是,太多的“教程”YouTube视频展示了使用ViewBags进行演示,并几乎没有提供任何关于何时不适用于生产代码的见解。是的,有时使用ViewBag可能是解决特定问题的合适方案,但可能会导致长时间的挫败感和较差的可维护性。冒着过度谨慎的风险,我鼓励年轻开发人员在他们更多地了解MVC、开发出自然的对ViewModels何时以及如何有用的感觉之后,不要依赖ViewBag,然后在此之后,再发展出更有经验的使用ViewBag的感觉。