【问题标题】:MVC ViewBag Best Practice [closed]MVC ViewBag 最佳实践 [关闭]
【发布时间】:2012-06-29 12:45:15
【问题描述】:

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

问题:

  1. 我的假设是否高于最佳实践。 (不要使用 ViewBag,其次要在视图模型中使用)

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

【问题讨论】:

  • 从微软的角度来看,我们不同意永远不要使用 ViewBag 或者 ViewBag 是 No No。使用 ViewBag 传递模型数据是另一回事,应该劝阻。使用 ViewBag 传递元数据(选择列表)很好。桑德森的 Pro MVC 和其他书籍使用它们并且没有做出这样的明确声明 - 2. 绝对必要 - 我对此表示怀疑。

标签: asp.net-mvc razor viewbag


【解决方案1】:

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

一般来说,使用视图模型在您的操作方法和视图之间传输数据是个好主意。视图模型是一个简单的 POCO 类,它具有特定于视图的属性。因此,如果您想向视图传递一些额外的数据,请向您的视图模型添加一个新属性并使用它。强类型视图使代码更清晰,更易于维护。使用这种方法,您无需来回将 viewbag 字典项显式转换为某些类型,而这与 view bag 相关。

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&lt;SelectListItem> 的属性,以传递下拉数据。这是一个post,其中包含有关如何执行此操作的示例代码。

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

在一些有效的用例中,您可以(不必要)使用 ViewBag 发送数据。例如,您想在 Layout 页面上显示某些内容,您可以使用 ViewBag 来实现。另一个例子是ViewBag.Title(对于页面标题)出现在默认 MVC 模板中。

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

并且在布局中,可以阅读ViewBag.AnnouncementForEditors

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

【讨论】:

  • 模型是存放在ViewBag中的,所以总是必须要有的。使用魔术字符串可能不是可维护性的顶峰,但除了使用模型所做的所有事情之外,还要强制执行声明类型和页面变量的约定。
【解决方案2】:

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

您应该尽可能使用视图模型而不是通过 ViewBag 传递数据。

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

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

【讨论】:

  • 与我们 (MS) 发布的指南一致的出色响应。我只会将其从传递数据更改为传递模型数据(元数据除外)参见我的教程底部asp.net/mvc/tutorials/javascript/…
  • @RickAndMSFT,我必须管理我第一次学习 ViewBags 时利用了你的帖子。顺便说一句,很棒的帖子。
  • 好答案,我还认为使用 ViewBag 来污染视图模型,其中包含要传递给视图的选项列表是一个好习惯。如果在 ViewModel 中传递了一个列表,那是因为该列表可能会被编辑,或者因为它对模型“有意义”。但是对于只选择一个的选项列表,ViewBag 看起来更干净。
  • 我认为使用动态类型的所有缺点都比污染视图模型要糟糕得多。如果不通读整个控制器,您甚至无法查看视图并了解视图包中设置的内容。
【解决方案3】:

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

是的。

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

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

【讨论】:

  • 元数据呢?我们应该从模板中抽出@ViewBag.Title 吗?
  • 是的,扔掉它。请。我不想在 ASP.NET MVC 4 中看到。这让我想吐。如果您愿意,可以在框架内部使用它,但将其标记为 internal,以便开发人员永远不必面对它。
【解决方案4】:

ViewBags 的问题和推荐的最佳实践归结为编译时检查。 ViewBags 只是字典,你会得到“神奇”的字符串,所以如果你最终改变了一个 viewbag 项目的对象类型或你直到运行时才知道的键名,即使你使用 @987654321 预编译视图@。

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

【讨论】:

    【解决方案5】:

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

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

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

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

    埃里克

    【讨论】:

    • 我知道这是旧的,但使用部分作为作业列表和 @{Html.RenderAction("SomeAction", "SomeController");} 从视图中使用不是更好吗?
    【解决方案6】:
    1. 没有。使用ViewModels。
    2. 没有。如果您设计了完美的 ViewModel,则永远不需要 ViewBag。

    【讨论】:

      【解决方案7】:

      如果您无法重新设计现有的 ViewModel,请使用 ViewBag。

      【讨论】:

        【解决方案8】:

        我想我会就此发表自己的看法,因为我已经广泛使用了 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

        【讨论】:

          【解决方案9】:

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

          在某些情况下,您需要在布局、视图和局部视图之间共享来自控制器的数据。在这种情况下,ViewBag 非常有用,我怀疑有没有更好的方法。

          【讨论】:

            【解决方案10】:

            如果没有它的用​​例,它一开始就不会实施。是的,您可以使用 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。

            【讨论】:

              【解决方案11】:

              冒着在这里打开一罐旧蠕虫的风险,让我提供一点见解。不管什么可能是“最佳实践”,让我提供真实世界的经验,即 ViewBag 的广泛使用可能是琐碎的噩梦来源,很难找到错误和问题,这些问题和追踪和解决完全令人讨厌。即使可以为使用 ViewBag 建立一个令人满意的概念或规则,它们也很容易成为初级开发人员的拐杖,以分散注意力并阻止开发适当的强类型 ViewModel。

              不幸的是,太多的“教程”YouTube 视频展示了 ViewBags 用于演示目的,并且几乎没有提供关于这种做法何时不适合生产代码的见解。是的,有时使用 ViewBag 可能是解决给定问题的合适解决方案,但可能会导致漫长而曲折的挫折之路和可维护性差。冒着过度纠正谨慎方向的风险,我会鼓励年轻的开发人员不要依赖 ViewBag,直到他们获得更多 MVC 经验,培养对何时和ViewModel 是如何有用的,然后在此之后对何时适合使用 ViewBag 形成更老练的感觉。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-10-02
                • 2010-10-06
                • 2011-10-28
                • 2010-09-10
                • 2011-10-11
                相关资源
                最近更新 更多