ASP.NET MVC 应用程序中数据传递方式的初学者教程






4.90/5 (41投票s)
本文将讨论 ASP.NET MVC 应用程序中几种重要的数据传输技术
引言
本文将讨论 ASP.NET MVC 中几种重要的数据传输技术,即 ViewData
、ViewBag
、TempData
和老式的 Session
变量。我们将尝试探讨何时使用它们,以及它们各自的优缺点。
背景
在我们之前的文章中,我们讨论了 MVC 的基础知识以及 MVC 提供的优势(请参考:ASP.NET MVC for Web Forms 开发者绝对初学者教程[^])。在本文中,我们将讨论如何将数据从 Controller
传输到 View
,或在控制器的操作之间传递数据。
模型
将数据从 Controller
传递到 View
的最佳和推荐方式是使用 Model
类。如果我们创建一个强类型视图,那么该视图就能够访问从控制器传递给它的对象/模型。因此,在大多数需要使用数据的情况下,我们应该创建强类型视图并将 Model
对象传递给视图。
当我们谈论 Model
类时,主要有三种类型的 Model 类。第一种是代表我们数据模型的实体。第二种是代表我们应用程序领域模型的类。从应用程序的角度来看,我们大部分时间会在视图中使用这些领域模型,以便可以提取应用程序数据并将其显示在视图中。如果需要直接显示数据模型中的数据,我们也可以直接使用实体。
ViewModel
现在考虑一个场景,我们需要创建一个视图,该视图需要来自两个或更多类/模型的数据。我们如何创建一个可以从两个模型中提取数据的强类型视图?答案是我们不能。但是我们可以创建一个新类,该类可以包含这些类的对象,并且这个类可以作为模型类传递给视图。现在,这个类被创建用于某些视图的模型。所有此类类都称为 ViewModels
。
ViewData 和 ViewBag
我们看到了如何使用 Models 和 ViewModels
将数据从控制器传递到视图。但现在考虑一个场景,我们需要从控制器向视图传递少量数据。现在,对于每个这样的情况,如果开始创建 ViewModels
,那么管理这些视图模型将成为一场噩梦。对于所有需要传输少量数据的此类要求,我们可以使用 Viewdata
和 ViewBag
。
视图数据
ViewData
是一个内置的字典对象,可以使用字符串类型的键值进行访问和设置。它派生自 ViewDataDictionary
类,在将数据从 Controller 传递到 View 时是一个非常方便的数据结构。数据只在一次请求中有效,不能在请求之间持久化。ViewData
的唯一问题是,在提取数据的位置,对于复杂数据类型需要进行类型转换。
ViewBag
C# 4.0 提供了动态变量的可能性。ViewBag
数据结构就是为了利用这一点而创建的,它作为 ViewData
的一个包装器,因此如果我们使用 ViewBag
,则无需对复杂对象进行类型转换。ViewBag
具有 ViewData
的所有优点,此外还不需要类型转换。
TempData
现在,上述所有数据传输方式的问题在于数据只在当前请求中有效。如果发生重定向,即一个 Action 重定向到另一个 Action,数据就会丢失。对于需要在 Action/重定向之间持久化数据的场景,可以使用另一个名为 TempData
的字典对象。它派生自 TempDataDictionary
。它是在会话之上创建的。它将一直存在,直到重定向的视图完全加载。
会话
Session
是在当前会话有效期间持久化数据的方式。如果我们需要一些数据能够从多个控制器、操作和视图中访问,那么 Session 是存储和检索数据的方式。
使用代码
现在让我们创建一个简单的 MVC 3.0
Web 应用程序,使用 razor
视图来演示上述所有数据传输方法。
模型
首先,让我们看看如何创建一个强类型视图,该视图将显示从控制器传递给它的数据。我们先有一个简单的模型,例如
public class Book
{
public int ID { get; set; }
public string BookName { get; set; }
public string Author { get; set; }
public string ISBN { get; set; }
}
现在,让我们创建一个名为 SampleBook
的简单 Action,并在其中创建一个 book 对象,然后将其传递给视图。
public ActionResult SampleBook()
{
Book book = new Book
{
ID = 1,
BookName = "Sample Book",
Author = "Sample Author",
ISBN = "Not available"
};
return View(book);
}
现在,让我们为此操作添加一个强类型视图,该视图将使用 Book
模型来检索数据。我们还使用“Details
”支架,这样我们就不必编写从模型访问数据的代码(仅用于演示目的)。

现在,如果我们查看视图的代码,我们可以看到数据是从控制器传递的 Book
类型的 Model
对象中提取的。

当我们运行应用程序时

ViewModel
现在,假设我们需要一个视图来显示来自多个模型的数据。假设我们有另一个类获取一些自定义消息,并且每当显示 Book
数据时,该消息都应显示在页面上。现在,此消息数据包含在另一个模型中,如下所示:
public class Message
{
public string MessageText { get; set; }
public string MessageFrom { get; set; }
}
现在我们需要将两个对象传递给视图,一个 Book 对象和另一个 Message
对象。为此,我们需要创建一个新类,即 ViewModel
类,它将包含这两个对象。
public class ShowBookAndMessageViewModel
{
public Book Book { get; set; }
public Message Message {get;set;}
}
现在,让我们的控制器中再创建一个动作。这个动作将创建这个 ViewModel
对象并将其传递给视图。
public ActionResult SampleBook2()
{
Book book = new Book
{
ID = 1,
BookName = "Sample Book",
Author = "Sample Author",
ISBN = "Not available"
};
Message msg = new Message
{
MessageText = "This is a Sample Message",
MessageFrom = "Test user"
};
ShowBookAndMessageViewModel viewModel = new ShowBookAndMessageViewModel
{
Message = msg,
Book = book
};
return View(viewModel);
}
现在,让我们创建一个强类型视图,它将使用此 ViewModel
类来提取数据。

现在让我们看看从这个 ViewModel
中提取数据并将其显示在视图上所需的代码。

当我们运行应用程序时,我们可以看到数据可以从这个 ViewModel
类中提取,然后从 Book
和 Message
类中提取相应的数据并显示在 View 上。
视图数据
我们已经讨论过,ViewData
可以用来将简单而少量的数据从控制器传递到视图。让我们看看如何使用 ViewData
将一个简单的消息字符串从控制器传递到视图。
public ActionResult Index()
{
ViewData["Message"] = "This Message is coming from ViewData";
return View();
}
现在可以从视图中提取此数据,如下所示:

当我们运行应用程序时

注意:我们在视图中没有进行类型转换,因为它只是一个简单的字符串。如果这些数据是某种复杂类型,类型转换将变得不可避免。
ViewBag
现在,让我们尝试实现与上述相同的功能,但使用 ViewBag
而不是 ViewData
。
public ActionResult Index2()
{
ViewBag.Message = "This Message is coming from ViewBag";
return View();
}
现在可以从视图中提取此数据,如下所示:

当我们运行应用程序时

TempData
现在,假设我们有一个动作方法重定向到另一个动作方法,并且我们需要将一些数据从一个动作方法传递到另一个动作方法。要做到这一点,我们将不得不使用 TempData
。
public ActionResult SampleBook3()
{
Book book = new Book
{
ID = 1,
BookName = "Sample Book",
Author = "Sample Author",
ISBN = "Not available"
};
TempData["BookData"] = book;
return RedirectToAction("SampleBook4");
}
public ActionResult SampleBook4()
{
Book book = TempData["BookData"] as Book;
return View(book);
}
当调用 SampleBook3
action 时,它将创建一个 Book 类型,将其放入 TempData
变量中,然后重定向到 action SampleBook4
。现在在 SampleBook4
中,数据将从 TempData
中提取,然后显示 SampleBook4
的 View,它是一个强类型视图,能够显示 Book 模型中的数据。
Session
对于 Web 开发人员来说,会话的使用没有什么新鲜之处。我们可以使用会话变量来持久化数据直到当前会话结束。为了演示这一点,让我们使用会话而不是 TempData
来实现上述功能。
public ActionResult SampleBook5()
{
Book book = new Book
{
ID = 1,
BookName = "Sample Book",
Author = "Sample Author",
ISBN = "Not available"
};
Session["BookData"] = book;
return RedirectToAction("SampleBook6");
}
public ActionResult SampleBook6()
{
Book book = Session["BookData"] as Book;
return View(book);
}
当 SampleBook5
动作被调用时,它将创建一个 Book 类型,将其放入一个会话变量中,然后重定向到 SampleBook6
动作。现在在 SampleBook6
中,数据将从会话中提取,然后显示 SampleBook6
的视图,它是一个强类型视图,能够显示 Book 模型中的数据。
注意:示例应用程序包含演示所有技术的完整应用程序。请参阅示例应用程序以更好地理解。
关注点
本文讨论了在控制器和视图之间以及控制器中的操作之间传递数据的各种方法。本文是从 MVC 初学者的角度编写的。希望本文能为您提供有益的信息。
历史
- 2013 年 4 月 12 日:第一版。