2012-06-29 140 views
27

对于ViewBag,我听说这是一个不可以使用。 我会假设从ViewBag的内容应该被纳入视图模型?MVC ViewBag最佳实践

问:

  1. 是我的假设之上的最佳实践。 (不使用ViewBag,其次使用视图模型)

  2. 是否有ViewBag绝对必要的情况?

+7

从微软的角度来说,我们不同意从不使用ViewBag或ViewBag是没有用号到ViewBag传递模型数据又是另一回事,应该气馁。使用ViewBag传递元数据(选择列表)很好。由桑德森和其他书籍的Pro MVC使用它们,并没有做出这样的明确宣言 - 2.必要的绝对 - 我怀疑它。 – RickAndMSFT

回答

25

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>类型的属性,以传递下拉数据。这里是一个post与示例代码如何做到这一点。

是否有ViewBag绝对必要的情况?

有一些有效的使用情况下,您可以(不需要)使用ViewBag发送数据。例如,您想要在布局页面上显示某些内容,则可以使用ViewBag。另一个示例是默认MVC模板中存在的ViewBag.Title(用于页面标题)。

public ActionResult Create() 
{ 
    ViewBag.AnnouncementForEditors="Be careful"; 
    return View(); 
} 

而且在布局,可以用ViewBags阅读ViewBag.AnnouncementForEditors

<body> 
<h1>@ViewBag.AnnouncementForEditors</h1> 
<div class="container body-content"> 
    @RenderBody() 
</div> 
</body> 
+0

模型存储在ViewBag中,所以它始终是必需的。使用魔术字符串可能不是可维护性的高峰,但除了使用模型所做的所有操作之外,都强制声明类型和页面变量的约定。 –

0
  1. 号使用ViewModels
  2. 不。如果你设计了一个完美的ViewModel,你永远不需要ViewBag。
4

1)我的假设高于最佳实践。 (不使用ViewBag和 秒使其在视图模型中)

是的。

2)是否有ViewBag绝对必要的情况?

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

+0

元数据呢?我们应该从模板中抽出@ ViewBag.Title吗? – RickAndMSFT

+7

Yeap,把它扔掉。请。我不想在ASP.NET MVC 4中看到它。它让我想吐。如果您将其标记为“内部”,那么在框架内部使用它,这样开发人员就不必面对它。 –

4

的问题和建议的最佳实践归结编译时间检查。 ViewBag只是​​字典,因此你会得到'神奇'的字符串,所以如果你最终改变了其中一个viewbag项目的对象类型或者直到运行时才会知道的键名,即使你使用<MvcBuildViews>true</MvcBuildViews>预编译视图。

坚持查看模型是最好的,即使您必须一次又一次地修改它们以适合特定视图。

26

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

你应该通过ViewBag使用的ViewModels,而不是通过数据尽可能地。

2)是否有ViewBag绝对必要的情况?

在任何情况下ViewBag都是绝对必要的。但是,我个人更喜欢使用ViewBag而不是View Model的一些数据。例如,当我需要填充预定义值(例如城市)的下拉框时,我使用ViewBag来携带SelectListItem数组来查看。我不想用这些数据来污染我的ViewModels。

+4

符合我们(MS)公布的指导的出色响应。我只会将其从传递数据更改为传递模型数据(元数据除外)请参阅我的教程的底部http://www.asp.net/mvc/tutorials/javascript/working-with-the-dropdownlist-box-and -jquery/examining-how-aspnet-mvc-scaffolds-the-dropdownlist-helper – RickAndMSFT

+0

@RickAndMSFT,我必须管理当我第一次学习ViewBags时,我利用了你的帖子。好的文章。 – SadullahCeran

+1

好的答案,我也认为使用ViewBag而不是污染视图模型和一系列要传递给视图的选项是一种很好的做法。 如果列表在ViewModel中传递,这是因为列表可能会被编辑,或者因为它对模型“有意义”。但是对于只有一个选项的选项列表来说,ViewBag看起来更清晰。 – iberodev

2

我发现了ViewBag的一些用法,其中所有页面都具有通用功能,并且功能不依赖于显示的页面。例如,假设你正在构建StackOverflow。工作板显示在每个页面上,但显示的工作与页面无关(我的用法在概念上相似)。将属性添加到每个ViewModel将会很困难并且耗时,并且会对您的测试带来不便。在这种情况下,我认为这不值得。

我已经使用了交叉切割数据的基础ViewModel类,但是如果你多于一个(例如作业&堆栈交换站点列表),你必须开始填充额外的数据,或者其他一些滥用一个ViewModel,再加上你需要一个ViewModel构建器来填充基础数据。

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

说了这么多,如果你的页面上显示的东西取决于页面的上下文,ViewModel就是你的朋友。

埃里克

+0

我知道这是旧的,但它不会更好地使用部分作业列表和@ {Html.RenderAction(“SomeAction”,“SomeController”);}从视图? – wingyip

1

如果您不能重新设计现有视图模型使用ViewBag。

0

2.Are存在的情况下一个ViewBag是绝对必要的?

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

0

如果没有用例,它将不会被首先实现。是的,你可以用ViewModels做所有的事情,但是如果你不需要一个呢?其中一种情况是编辑实体。您可以直接将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个额外的ViewModels。