65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (41投票s)

2013年4月12日

CPOL

7分钟阅读

viewsIcon

210857

downloadIcon

2375

本文将讨论 ASP.NET MVC 应用程序中几种重要的数据传输技术

引言

本文将讨论 ASP.NET MVC 中几种重要的数据传输技术,即 ViewDataViewBagTempData 和老式的 Session 变量。我们将尝试探讨何时使用它们,以及它们各自的优缺点。

背景

在我们之前的文章中,我们讨论了 MVC 的基础知识以及 MVC 提供的优势(请参考:ASP.NET MVC for Web Forms 开发者绝对初学者教程[^])。在本文中,我们将讨论如何将数据从 Controller 传输到 View,或在控制器的操作之间传递数据。

模型

将数据从 Controller 传递到 View 的最佳和推荐方式是使用 Model 类。如果我们创建一个强类型视图,那么该视图就能够访问从控制器传递给它的对象/模型。因此,在大多数需要使用数据的情况下,我们应该创建强类型视图并将 Model 对象传递给视图。

当我们谈论 Model 类时,主要有三种类型的 Model 类。第一种是代表我们数据模型的实体。第二种是代表我们应用程序领域模型的类。从应用程序的角度来看,我们大部分时间会在视图中使用这些领域模型,以便可以提取应用程序数据并将其显示在视图中。如果需要直接显示数据模型中的数据,我们也可以直接使用实体。

ViewModel

现在考虑一个场景,我们需要创建一个视图,该视图需要来自两个或更多类/模型的数据。我们如何创建一个可以从两个模型中提取数据的强类型视图?答案是我们不能。但是我们可以创建一个新类,该类可以包含这些类的对象,并且这个类可以作为模型类传递给视图。现在,这个类被创建用于某些视图的模型。所有此类类都称为 ViewModels

ViewData 和 ViewBag

我们看到了如何使用 Models 和 ViewModels 将数据从控制器传递到视图。但现在考虑一个场景,我们需要从控制器向视图传递少量数据。现在,对于每个这样的情况,如果开始创建 ViewModels,那么管理这些视图模型将成为一场噩梦。对于所有需要传输少量数据的此类要求,我们可以使用 ViewdataViewBag

视图数据

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 类中提取,然后从 BookMessage 类中提取相应的数据并显示在 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 日:第一版。
© . All rights reserved.