你如何决定从asp.net mvc控制器传递模型数据到视图的方式?

3
有多种方法可以将模型数据从asp.net mvc的控制器传递到视图。对我来说,mvc v1和v2版本中是否有推荐的方法还不清楚,可能像生活中的大多数事情一样,这取决于具体情况。我见过几种方法:
选项1-使用控制器的ViewData字典,在视图中通过icky基于字符串索引的方式进行类型转换,或者使用强类型自定义模型类以强类型方式传递该模型数据。
选项2-使用ViewData.Model,但我甚至不确定它的含义。
选项3-使用ViewPage.Model,在这种情况下,我不知道如何从控制器传递模型数据。
我看过很多帖子批评选项1和2,但我不明白为什么。在大多数情况下,这些帖子似乎高度推荐选项3。
您如何处理这个问题?是否有标准方法?
4个回答

2

每个视图都应该有一个特定的模型。这有时需要更多的工作,因此人们使用像ViewData这样的快捷方式,这种方法可以工作,但在我看来不够干净和类型安全,所以我更喜欢将所有内容放在视图的模型中。

然后,您可以使所有视图强类型化。这是一种非常干净的方法。然后在控制器中,您只需调用视图,如下所示:

YourViewModel model = new YourViewModel()
{
    // initialize the data here
};
View(model);

然后在您的视图中,可以通过 ViewPage Model 访问所有数据,并且它是类型安全的,同时也从控制器进行了强制执行。

来自评论的编辑:

如果不需要使用 ViewData,您完全可以将视图所需的所有数据封装在一个模型中,就像您引用 ProductsListViewData 的示例一样。它只是一个包含要存储在 ViewData 中的所有项的模型。两种方式都可以,但当您将其封装在类中(优先使用方法,其中所有部分都是模型中的)时,所有组件都是强类型的。

ViewData 是一个通用容器,因此即使您可以将任何内容放入其中,但它不是类型安全的,因此不太“干净”。这取决于偏好和可维护性。只有选项1和3。您的选项2被误解了,实际上只是选项3。没有 ViewData.Model,只有 ViewPage.Model


+1 是因为你很灵活,不会说你总是需要一个强类型模型。 - John Farrell
感谢您的出色回答。有几个后续问题:首先,您的YourViewModel类是否与http://bit.ly/eWN6R中显示的“使用强类型类传递ViewData”的“方法2:Passing ViewData”部分中显示的ProductsListViewData相同?其次,我的Option 1和Option 2都涉及ViewData,但我不清楚何时通过ViewPage.ViewData [“whatever”]访问ViewData,而何时通过ViewData.Model访问? - Emilio
非常感谢,你完全为我澄清了这两个问题。 - Emilio
@Emilio 如果这个回答解决了你的问题,请不要忘记将其设置为被接受的答案 :) 我会将我的评论移到答案上面,以便其他人不会错过它们。 - Kelsey
都准备好了。你认为下面的答案和评论怎么样? - Emilio

1

随着您的视图变得更加复杂,您可能希望考虑一种方法,即保留使用模型来支持输入字段,并使用ViewData来支持视图需要呈现的任何其他内容。

至少有几个论点支持这一点:

  1. 您有一个主页需要某些数据存在(例如标题中类似于StackOverflow用户信息的内容)。应用站点范围的ActionFilter可以轻松地在每个操作后将此信息填充到ViewData中。如果要将其放入模型中,则需要使站点中的每个其他模型都继承自基本模型(最初可能看起来不错,但很快就会变得复杂)。

  2. 当您验证已发布的表单时,如果存在验证错误,则可能需要将模型(带有无效字段)重新绑定回视图并显示验证消息。这是可以的,因为输入字段中的数据被发布并将绑定到模型,但是视图需要重新填充的任何其他数据呢?(例如下拉列表值、信息消息等)这些不会被发布回来,而且在“周围”发布回来的输入值上重新填充这些数据可能会变得混乱。通常更简单的方法是编写一个方法,用于将ViewData填充为视图数据。

根据我的经验,我发现这种方法很有效。

而且,在MVC3中,动态ViewModels意味着不再需要使用字符串索引!


我完全同意。对于所有事情都使用模型会变得非常混乱和难以管理。在适用的情况下使用ViewData。他们没有把它放在那里是为了让我们不使用它。 - Yngve B-Nilsen

0

0

我知道下面的答案可能存在争议,但这只是我喜欢的方式。

我会建议在处理简单数据任务时使用ViewData,在处理视图主要目的时使用Model。可以查看Rob Conery的ViewData帮助类,以使它们具有更强的类型感觉:

http://blog.wekeroad.com/2010/01/20/my-favorite-helpers-for-aspnet-mvc

对于绝大多数事情都使用模型会使你的项目膨胀成数百个模型,即使是实现最小的功能。我的意思是,如果你有一个用户设置页面,通常会将User-model传递到视图中,但如果你决定显示一些相关数据,比如与该用户相关的客户。你就会陷入以下解决方案:

  1. 你可能需要向User-model添加一个List属性,以便在视图中公开客户。这导致Customer-property始终应用于项目中的所有其他地方的User-model - 或者创建一个新的更简单的User-model。
  2. 创建一个返回部分客户的新操作,可以使用Html.RenderAction。

或者

你可以这样做:ViewData["Customers"] = myRepo.GetCustomersRelatedTo(user); //或类似的方法。

并且(如果使用Robs helpers)在你的视图中:

<%= Html.RenderPartial("CustomerList", Html.ViewData("Customers")) %> 添加一个名为CustomerList的PartialView,它接受IEnumerable

在我看来,这是一个更清晰的解决方案,当然,你最终会得到一些魔术字符串,但除非有人向我展示一个没有任何魔术字符串的项目,否则我会坚持这种方法。

使用框架中提供的工具来完成工作。保持简单,让事情变得更容易... ;)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接