如何选择在 ASP.NET MVC 中传递多个模型的最优方式






4.80/5 (74投票s)
如何选择在 ASP.NET MVC 中传递多个模型的最优方式
引言
在本文中,我们将讨论如何选择从控制器到视图传递多个模型的最佳方式。在上一篇文章 “在 ASP.NET MVC4 的视图中使用多个模型” 中,我们已经介绍了 6 种方法,即 ViewModel、部分视图 (Partial View)、Tuple、ViewData、ViewBag 和 TempData。在选择一种适合特定场景的方法时,我们可能会感到困惑。在这篇文章中,我将分享我对这个话题的见解。
如果您还没有阅读我们关于 在 ASP.NET MVC4 的视图中使用多个模型 的上一篇文章,请务必看一下,因为当前这篇文章是基于该文章的。上一篇文章详细讨论了如何将多个模型从控制器传递到视图,并附带了一个 ASP.NET MVC 4 的演示应用程序。这将帮助您更好地理解当前的文章。
方法概述
上一篇文章中描述的所有六种方法都有其各自的优缺点。选择哪种方法取决于具体的场景,这当然是一个有争议的话题。在做出任何决定之前,我们需要准确地识别需求,然后才能通过比较优缺点来选择其中一种方法。在本文中,我想将这些方法按照在 ASP.NET MVC 应用程序中使用的频率从高到低排列,如下所示:
- ViewModel
- 部分视图
- ViewBag
- 视图数据
- TempData
- 元组
应用程序可以根据特定时刻的需求使用一种以上的方法。 我们需要根据当前的需求来考虑最佳方法。
现在我们将详细讨论上述方法、它们的用法、相关的优缺点。
ViewModel
ViewModel 是一种模式,它允许我们将多个模型作为一个类来处理。它根据视图的需求聚合模型或包含它们的属性。ViewModel 不应该包含方法,它应该是一个视图所需属性的集合。
典型用法
这是在企业应用程序中将多个模型传递到视图的最常用方法。当您需要在视图中显示多个模型时(也可用于部分视图),这是您可以使用的方法。这是标准方法。
优点
- ViewModel 允许我们将多个模型类型作为单个模型在视图中进行渲染。
- 在视图页面上提供出色的 IntelliSense 支持和编译时错误检查。
- ViewModel 在安全方面也很有优势,因为视图只包含它们确切需要的内容。核心域模型不会暴露给用户。
- 如果核心域模型有任何更改,您不需要在视图代码中进行任何更改,只需修改相应的 ViewModel 即可。
- 通过这种方式,ViewModel 促进了应用程序的松耦合。
缺点
- ViewModel 在模型 (Models) 和视图 (Views) 之间增加了另一层,因此会稍微增加复杂性。因此,对于小型和演示应用程序,我们可以使用 Tuple 或其他方式来保持演示的简单性。
部分视图
部分视图 (Partial View) 是一个您可以在父视图中包含的子视图。在很多情况下,我们会遇到很多视图具有共享/公共表示的情况,这种公共表示会被分离成一个部分视图并在其他视图中使用。
典型用法
这种方法在企业应用程序中也与 ViewModel 一起频繁使用。当您需要在多个视图中共享相同的代码(Razor 和 HTML 代码)时,可以使用它。
优点
- 它促进了应用程序中代码(Razor 和 HTML 代码)的重用。
- 对于单页应用程序非常有用。
- 您也可以将 ViewModel 方法用于部分视图。
- 使用部分视图,您可以使用 AJAX 在不刷新整个页面的情况下更新视图的特定区域。
缺点
- 如果过度使用,视图将变成部分视图的简单聚合,有时会影响可读性。
ViewBag
ViewBag 是一个动态属性,它来自 `ControllerBase` 类。内部 `ViewBag` 属性以键值对的形式存储在字典中。它利用了 C# 4.0 中的新动态特性,因此 `ViewBag` 不需要对数据类型进行类型转换。
典型用法
在 ASP.NET MVC 3.0 及更高版本中,它应该用于属性直接与视图相关且不适合作为模型(模型应该是一个封装业务数据和行为的类)的情况。`ViewBag` 的典型示例是使用 `ViewBag.Title` 设置视图的标题,或者在视图中显示消息,如 `ViewBag.Message` 等。
优点
- 使用 `ViewBag`,我们可以轻松地将数据从控制器发送到视图。
- `ViewBag` 的语法比 `ViewData` 更好。不需要使用键。
- `ViewBag` 不需要对数据类型进行类型转换。
缺点
- 它仅用于单向传输数据,即从控制器到视图。
- `ViewBag` 的值仅在当前请求期间有效。它的值不能在请求之间持久化,因此如果发生重定向,其值将变为 `null`。
- 过度使用 `ViewBag` 绝对是一种坏习惯。不推荐在企业应用程序中使用它,尽管有时也可能用于传输少量数据。
- 没有 IntelliSense 支持和编译时错误检查。
- 技术上讲,它比 `ViewData` 慢,但在实际场景中,差异微乎其微。(而且,首先,微观优化是糟糕的。)
视图数据
`ViewData` 在 `ControllerBase` 类中被定义为一个属性(`ViewDataDictionary` 类的类型)。存储在 `ViewData` 中的值在视图中需要转换为其数据类型。`ViewData` 中的值可以使用键来访问。
典型用法
在 ASP.NET MVC 版本 1 和 2 中,它用于与 `ViewBag` 相同的目的。Microsoft 支持新版本中的 `ViewData`,但由于 `ViewBag` 提供了更多优势,因此最好不要在最新版本的 MVC 中使用 `ViewData`。
优点
- 使用 `ViewData`,我们可以使用内置的键功能将数据从控制器发送到视图。
缺点
- 它仅用于单向传输数据,即从控制器到视图。
- `ViewData` 的值仅在当前请求期间有效。它的值不能在请求之间持久化,因此如果发生重定向,其值将变为 `null`。
- 过度使用 `ViewData` 绝对是一种坏习惯。不推荐在企业应用程序中使用它,尽管有时也可能用于显示少量数据。
- 使用键语法,因此不如使用属性式语法的 `ViewBag` 可读。
- 没有 IntelliSense 支持和编译时错误检查。
TempData
`TempData` 在 `ControllerBase` 类中被定义为一个属性。它是一种 `TempDataDictionary` 类。存储在 `TempData` 中的值在视图中需要转换为其数据类型。`TempData` 中的值可以使用键来访问。它类似于 `ViewData`,但不同之处在于它允许我们将数据从一个控制器发送到另一个控制器,以及从一个操作发送到另一个操作。这是可能的,因为它内部使用了 session 变量。
典型用法
当您需要将某些信息保留到后续请求时,使用 `TempData` 是个好主意。当您需要保留诸如验证消息、错误消息或一些不包含敏感信息的少量数据时,应使用它。由于它维护 session 来传递值,因此您不应该在 `TempData` 中存储敏感数据。
优点
- 您可以将值从一个操作传递到另一个操作,或从一个控制器传递到另一个控制器。
缺点
- 如上所述,它可能会引入安全风险。
- 它需要对数据类型进行类型转换,并检查 `null` 值以避免错误。
- 在 Visual Studio 中没有 IntelliSense 支持。
元组
Tuple 是 .NET Framework 4.0 中引入的一个新类。它是一个有序序列、不可变、固定大小的异构(允许我们组合多种数据类型)对象集合。
典型用法
它可能适用于小型和演示应用程序。Tuple 是 C# 语言的一个特性,适用于特定场景(此处描述),但如果您在 ASP.NET MVC 中使用它,只有当您不想创建 ViewModel 时,才应该使用 Tuple。
优点
- 它提供了一种在不创建新类(ViewModel)的情况下聚合模型的方式。
- 一种快速的解决方案,比 ViewModel 需要更少的编码工作。
缺点
- Tuple 是固定大小的,最多可以包含 8 个项目。
- 值以 `item1`、`item2`... 的形式传递。仅从代码中很难识别参数。
- 在 Visual Studio 中没有出色的 IntelliSense 支持。
结论
在本文中,我们学习了如何在 ASP.NET MVC 应用程序中选择传递多个模型的最佳方式。我希望这篇文章能帮助您以高效的方式理解和使用这些概念。欢迎您提出问题和评论。谢谢。
参考文献
- [1] http://stackoverflow.com/questions/664205/viewmodel-best-practices
- [2] https://codeproject.org.cn/Articles/193537/C-4-Tuples
- [3] http://stackoverflow.com/questions/1500402/when-to-use-tempdata-vs-session-in-asp-net-mvc
- [4] http://www.webcodeexpert.com/2013/12/what-is-use-of-viewbag-viewdata-and_3.html