前言
本文主要讲解如何正确使用 ViewData与ViewBag,以及他们之间的使用场景。首先需要知道,向视图中传递数据(从控制器中或者模型中)有两种类型:强类型与弱类型。
- 强类型数据:viewmodel(安全,官方推荐)
- 弱类型数据
ViewData
(ViewDataAttribute
)ViewBag
使用 viewmodel 将数据传递给视图可让视图充分利用强类型检查。 强类型化(或强类型)意味着每个变量和常量都有明确定义的类型(例如 string
、int
或 DateTime
)。 在编译时检查视图中使用的类型是否有效。
Visual Studio 和 Visual Studio Code 列出了使用 IntelliSense 功能的强类型类成员。 如果要查看 viewmodel 的属性,请键入 viewmodel 的变量名称,后跟句点 (.
)。 这有助于提高编写代码的速度并降低错误率。
可随意对 viewmodel 类型和业务模型类型使用相同的类。 但是,使用单独的模型可使视图独立于应用的业务逻辑和数据访问部分。 模型为用户发送给应用的数据使用模型绑定和验证时,模型和 viewmodel 的分离也会提供安全优势。
弱类型数据
除了强类型视图,视图还可以访问弱类型(也称为松散类型)的数据集合。 与强类型不同,弱类型(或松散类型)意味着不显式声明要使用的数据类型。 可以使用弱类型数据集合将少量数据传入及传出控制器和视图。
传递数据于... | 示例 |
---|---|
控制器和视图 | 用数据填充下拉列表。 |
视图和布局视图 | 从视图文件设置布局视图中的 < title>元素内容。 |
分部视图和视图 | 基于用户请求的网页显示数据的小组件 |
可以通过控制器和视图上的 ViewData
或 ViewBag
属性来引用此集合。 ViewData
属性是弱类型对象的字典。 ViewBag
属性是 ViewData
的包装器,为基础 ViewData
集合提供动态属性。 注意:对于 ViewData
和 ViewBag
,键查找都不区分大小写。
ViewData
和 ViewBag
在运行时进行动态解析。 由于它们不提供编译时类型检查,因此使用这两者通常比使用 viewmodel 更容易出错。 出于上述原因,一些开发者希望尽量减少或根本不使用 ViewData
和 ViewBag。
ViewData
ViewData
是通过 string
键访问的 ViewDataDictionary 对象。 字符串数据可以直接存储和使用,而不需要强制转换,但是在提取其他 ViewData
对象值时必须将其强制转换为特定类型。 可以使用 ViewData
将数据从控制器传递到视图,以及在视图(包括分部视图和布局)内传递数据。
以下是在操作中使用 ViewData
设置问候语和地址值的示例:
public IActionResult SomeAction()
{
ViewData["Greeting"] = "Hello";
ViewData["Address"] = new Address()
{
Name = "Steve",
Street = "123 Main St",
City = "Hudson",
State = "OH",
PostalCode = "44236"
};
return View();
}
在视图中处理数据
@{
// Since Address isn't a string, it requires a cast.
var address = ViewData["Address"] as Address;
}
@ViewData["Greeting"] World!
<address>
@address.Name<br>
@address.Street<br>
@address.City, @address.State @address.PostalCode
</address>
ViewData 特性
另一种会使用 ViewDataDictionary 的方法是 ViewDataAttribute。 控制器或 Razor 页面模型上使用 [ViewData]
属性的属性将其值存储在字典中并从中进行加载。
在下面的示例中,“主页”控制器包含使用 [ViewData]
标记的 Title
属性。 About
方法设置“关于”视图的标题:
public class HomeController : Controller
{
[ViewData]
public string Title { get; set; }
public IActionResult About()
{
Title = "About Us";
ViewData["Message"] = "Your application description page.";
return View();
}
}
在“关于”视图中,以模型属性的形式访问 Title
属性:
<h1>@Model.Title</h1>
在布局中,从 ViewData 字典读取标题:
<!DOCTYPE html>
<html lang="en">
<head>
<title>@ViewData["Title"] - WebApplication</title>
...
ViewBag
ViewBag
在 Razor Pages 中不可用。
ViewBag
是 DynamicViewData 对象,可提供对存储在 ViewData
中的对象的动态访问。 ViewBag
不需要强制转换,因此使用起来更加方便。 下例演示如何使用与上述 ViewData
有相同结果的 ViewBag
:
public IActionResult SomeAction()
{
ViewBag.Greeting = "Hello";
ViewBag.Address = new Address()
{
Name = "Steve",
Street = "123 Main St",
City = "Hudson",
State = "OH",
PostalCode = "44236"
};
return View();
}
@ViewBag.Greeting World!
<address>
@ViewBag.Address.Name<br>
@ViewBag.Address.Street<br>
@ViewBag.Address.City, @ViewBag.Address.State @ViewBag.Address.PostalCode
</address>
同时使用 ViewData 和 ViewBag
ViewBag
在 Razor Pages 中不可用。
由于 ViewData
和 ViewBag
引用相同的基础 ViewData
集合,因此在读取和写入值时,可以同时使用 ViewData
和 ViewBag
,并在两者之间进行混合和匹配。
在 About.cshtml 视图顶部,使用 ViewBag
设置标题并使用 ViewData
设置说明
@{
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "About Contoso";
ViewData["Description"] = "Let us tell you about Contoso's philosophy and mission.";
}
读取属性,但反向使用 ViewData
和 ViewBag
。 在 _Layout.cshtml 文件中,使用 ViewData
获取标题并使用 ViewBag
获取说明
<!DOCTYPE html>
<html lang="en">
<head>
<title>@ViewData["Title"]</title>
<meta name="description" content="@ViewBag.Description">
...
请记住,字符串不需要为 ViewData
进行强制转换。 可以使用 @ViewData["Title"]
而不需要强制转换。
可同时使用 ViewData
和 ViewBag
也可混合和匹配读取及写入属性。 呈现以下标记:
<!DOCTYPE html>
<html lang="en">
<head>
<title>About Contoso</title>
<meta name="description" content="Let us tell you about Contoso's philosophy and mission.">
...
差异
ViewBag
在 Razor 页中不可用。
ViewData
- 派生自 ViewDataDictionary,因此它有可用的字典属性,如
ContainsKey
、Add
、Remove
和Clear
。 - 字典中的键是字符串,因此允许有空格。 예:
ViewData["Some Key With Whitespace"]
- 任何非
string
类型均须在视图中进行强制转换才能使用ViewData
。
- 派生自 ViewDataDictionary,因此它有可用的字典属性,如
ViewBag
- 派生自 DynamicViewData,因此它可使用点表示法 (
@ViewBag.SomeKey = <value or object>
) 创建动态属性,且无需强制转换。ViewBag
的语法使添加到控制器和视图的速度更快。(其实差不多) - 更易于检查 NULL 值。 예:
@ViewBag.Person?.Name
- 派生自 DynamicViewData,因此它可使用点表示法 (
何时使用 ViewData 或 ViewBag
ViewData
和 ViewBag
都是在控制器和视图之间传递少量数据的有效方法。 根据偏好选择使用哪种方法。 可以混合和匹配 ViewData
和 ViewBag
对象,但是,使用一致的方法可以更轻松地读取和维护代码。 这两种方法都是在运行时进行动态解析的,因此容易造成运行时错误。 因而,一些开发团队会避免使用它们。
建议
在控制器和视图之间传递少量数据时,比如排序时的排序字符串,可使用ViewData
。一些简单的处理逻辑用弱类型还是方便的
参考文献:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/overview?view=aspnetcore-2.2