MVC ViewBag最佳实践

时间:2012-06-29 12:45:16

标签: asp.net-mvc razor viewbag

对于ViewBag,我听说这是禁止使用的。 我会假设ViewBag中的内容应该合并到视图模型中吗?

问题:

  1. 我的假设是否是最佳做法。 (不使用ViewBag,第二个在视图模型中使用它)

  2. 是否存在绝对需要ViewBag的情况?

10 个答案:

答案 0 :(得分:30)

  

1)我的假设是否是最佳实践。 (不要使用ViewBag和   第二个在视图模型中拥有它)

您应该使用viewmodels,而不是尽可能通过ViewBag传递数据。

  

2)是否存在绝对需要ViewBag的情况?

没有绝对需要ViewBag的情况。但是,有些数据我个人更喜欢使用ViewBag而不是View Model。例如,当我需要填充预定义值(即Cities)的下拉框时,我使用ViewBag来携带SelectListItem数组进行查看。我不想用这些数据污染我的ViewModel。

答案 1 :(得分:29)

ViewBag是一个动态字典。因此,当使用ViewBag在操作方法和视图之间传输数据时,如果在尝试访问视图中的ViewBag项时在代码中输入错误,编译器将无法捕获。您的视图将在运行时崩溃:(

通常,最好使用视图模型在操作方法和视图之间传输数据。 view model是一个简单的POCO类,它具有特定于视图的属性。因此,如果要传递一些额外的数据进行查看,请向视图模型添加新属性并使用该属性。强大的类型视图使代码更清晰,更易于维护。使用这种方法,您无需将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作为下拉数据。我个人仍然认为ViewBag不应该用于此。它应该是List<SelectListItem&gt;类型的属性。在您的视图模型中传递下拉数据。这是一个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>

答案 2 :(得分:4)

  

1)我的假设是否是最佳实践。 (不要使用ViewBag和   第二个在视图模型中拥有它)

  

2)是否存在绝对需要ViewBag的情况?

没有。您存储在ViewBag中的所有内容都可以进入传递给视图的视图模型。

答案 3 :(得分:4)

ViewBags的问题和推荐的最佳实践归结为编译时间检查。 ViewBags只是字典,你可以获得“魔术”字符串,所以如果最终改变其中一个视图包项目的对象类型或者直到运行时才会知道的键名,即使你使用{{预编译视图1}}。

坚持查看模型是最好的,即使你必须改变它们以适应特定的视图。

答案 4 :(得分:2)

我发现ViewBag有一些用途,其中所有页面都有共同的功能,而且功能不依赖于显示的页面。例如,假设您正在构建StackOverflow。作业板出现在每个页面上,但显示的作业与页面无关(我的用法在概念上类似)。向每个ViewModel添加属性将非常困难且耗时,并且您的测试中会出现批次。在这种情况下,我认为这不值得。

我已经使用了一个带有交叉数据的基本ViewModel类,但是如果您不止一个(例如,作业和堆栈交换站点列表),您必须开始填充额外的数据,或者其他一些滥用ViewModel,您还需要一个ViewModel构建器来填充基础数据。

至于魔术弦问题,有很多解决方案。常量,扩展方法等。

尽管如此,如果您的页面上显示的内容取决于页面的上下文,ViewModel就是您的朋友。

埃里克

答案 5 :(得分:1)

  1. 否。使用ViewModels
  2. 否。如果您设计一个完美的ViewModel,您永远不需要ViewBag。

答案 6 :(得分:1)

如果无法重新设计EXISTING ViewModel,请使用ViewBag。

答案 7 :(得分:0)

  

2.是否存在绝对需要ViewBag的情况?

在某些情况下,您需要跨布局,视图和部分视图共享Controller中的数据。在这种情况下,ViewBag非常有用,我怀疑还有更好的方法。

答案 8 :(得分:0)

如果没有用例,则不会首先实施。是的,你可以用ViewModel做任何事情,但是如果你真的不需要它呢?一种这样的场景是编辑实体。您可以直接将DTO作为模型传递。

@model CategoryDto
<div class="md-form form-sm">
    <input asp-for="Name" class="form-control">
    <label asp-for="Name">("Category Name")</label>
</div>

但是如果你想选择Category parent呢?实体DTO理想地仅包含它自己的值,因此要填充选择列表,请使用ViewBag

<select asp-for="ParentId" asp-items="ViewBag.ParentList">
    <option value="">None</option>
</select>

为什么这样?好吧,如果你有50种类型的实体,每种实体都有不同的值选择,你就可以避免创建50个额外的ViewModel。

答案 9 :(得分:0)

由于我已经广泛使用ViewBag,因此我想对此发表意见。

使用它的唯一真正好处是对于一个小型项目,或者在您有新项目并且只是想滚滚而不必担心创建模型类负载的情况下。< / p>

当项目更加成熟时,您可能会发现由于在整个应用程序中使用弱类型输入而导致的意外行为问题。发生错误时,逻辑可能会造成混淆,难以测试并且难以进行故障排除。

我实际上采用了从我的应用程序中完全删除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