【问题标题】:ViewBag, ViewData and TempDataViewBag、ViewData 和 TempData
【发布时间】:2011-12-21 01:14:09
【问题描述】:

谁能解释一下什么时候使用

  1. 临时数据
  2. 查看包
  3. 查看数据

我有一个要求,我需要在控制器一中设置一个值,该控制器将重定向到控制器二,控制器二将呈现视图。

我曾尝试使用 ViewBag,但当我到达控制器 2 时,该值会丢失。

我可以知道什么时候使用以及优缺点吗?

谢谢

【问题讨论】:

  • This 是一篇很好的文章,解释了这些差异。
  • stackoverflow.com/a/17199709/2015869

标签: asp.net-mvc-3


【解决方案1】:

1)临时数据

允许您存储在重定向后仍可保留的数据。在内部,它使用 Session 作为后备存储,在进行重定向后,数据会自动被驱逐。模式如下:

public ActionResult Foo()
{
    // store something into the tempdata that will be available during a single redirect
    TempData["foo"] = "bar";

    // you should always redirect if you store something into TempData to
    // a controller action that will consume this data
    return RedirectToAction("bar");
}

public ActionResult Bar()
{
    var foo = TempData["foo"];
    ...
}

2)ViewBag、ViewData

允许您将数据存储在将在相应视图中使用的控制器操作中。这假定该操作返回一个视图并且不重定向。仅在当前请求期间存在。

模式如下:

public ActionResult Foo()
{
    ViewBag.Foo = "bar";
    return View();
}

在视图中:

@ViewBag.Foo

或使用 ViewData:

public ActionResult Foo()
{
    ViewData["Foo"] = "bar";
    return View();
}

在视图中:

@ViewData["Foo"]

ViewBag 只是ViewData 的动态包装器,仅存在于 ASP.NET MVC 3 中。

话虽如此,这两种构造都不应该被使用。您应该使用视图模型和强类型视图。所以正确的模式如下:

查看模型:

public class MyViewModel
{
    public string Foo { get; set; }
}

行动:

public Action Foo()
{
    var model = new MyViewModel { Foo = "bar" };
    return View(model);
}

强类型视图:

@model MyViewModel
@Model.Foo

在这个简短的介绍之后,让我们回答你的问题:

我的要求是我想在控制器中设置一个值,即 控制器将重定向到 ControllerTwo 和 Controller2 将呈现 视图。

public class OneController: Controller
{
    public ActionResult Index()
    {
        TempData["foo"] = "bar";
        return RedirectToAction("index", "two");
    }
}

public class TwoController: Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel
        {
            Foo = TempData["foo"] as string
        };
        return View(model);
    }
}

以及对应的视图(~/Views/Two/Index.cshtml):

@model MyViewModel
@Html.DisplayFor(x => x.Foo)

使用 TempData 也有缺点:如果用户在目标页面上按 F5,数据将会丢失。

我个人也不使用 TempData。这是因为它在内部使用 Session 并且我在我的应用程序中禁用了会话。我更喜欢一种更 RESTful 的方式来实现这一点。即:在执行重定向的第一个控制器操作中,将对象存储在您的数据存储中,并在重定向时使用生成的唯一 ID。然后在目标操作上使用此 id 取回最初存储的对象:

public class OneController: Controller
{
    public ActionResult Index()
    {
        var id = Repository.SaveData("foo");
        return RedirectToAction("index", "two", new { id = id });
    }
}

public class TwoController: Controller
{
    public ActionResult Index(string id)
    {
        var model = new MyViewModel
        {
            Foo = Repository.GetData(id)
        };
        return View(model);
    }
}

视图保持不变。

【讨论】:

  • 很好的答案,但我不同意教条式的说法“这两种结构都不应该被使用”。我发现了 ViewBag 的一些合法用途。例如,我在我的所有视图上设置了一个ViewBag.Title 属性,该属性在我的_Layout.cshtml 基本视图文件中使用。我使用它的另一种情况是向用户提供信息消息(例如“产品保存成功!”)。我在Layout.cshtml 中放置了一些通用标记以呈现消息(如果提供),这允许我在任何操作中设置ViewBag.Message。在这两种情况下使用 ViewModel 属性都有很多缺点。
  • 我不得不同意 Jesse 的观点,虽然这是一个很好的描述,但公然说没有充分的理由使用 ViewBag 只是一个见仁见智的问题,而不是事实上的问题。过度使用 ViewBag 肯定是一种不好的做法,一些开发人员陷入了这个陷阱,但有品位地使用它是一种强大的资源。
  • @ron.defreitas,好吧,告诉我你为什么要使用ViewBag 的一个很好的理由。当 ViewBag 有一些用途时,请描述一个特定的真实世界场景。既然你说它是,我引用强大的资源,我猜你有一些特定的情况,这个强大的资源强大的。由于我在职业生涯中从未使用过它,我很高兴了解人们如何使用这种强大的武器。
  • 我们这里有一个精英。 Darin, Jesse 特别提到了一个这样的例子。仅仅因为总是有其他的做事方式并不会自动否定它们的用处。
  • @DarinDimitrov:我现在有一个场景,我需要从属性方法中将一些信息传递给视图。使用 filterContext.Controller.ViewData 比尝试将其传递给强类型视图要容易得多。也就是说,谢谢你的解释,它非常有用。
【解决方案2】:

临时数据

基本上它就像一个DataReader,一旦读取,数据就会丢失。

Check this Video

示例

public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewBag.Message = "Welcome to ASP.NET MVC!";
        TempData["T"] = "T";
        return RedirectToAction("About");
    }

    public ActionResult About()
    {
        return RedirectToAction("Test1");
    }

    public ActionResult Test1()
    {
        String str = TempData["T"]; //Output - T
        return View();
    }
}

如果你注意上面的代码,在读取 TempData 之前,RedirectToAction 对 TempData 没有影响。因此,一旦读取 TempData,值就会丢失。

TempData 读取后如何保存?

检查 Action Method Test 1 和 Test 2 中的输出

public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewBag.Message = "Welcome to ASP.NET MVC!";
        TempData["T"] = "T";
        return RedirectToAction("About");
    }

    public ActionResult About()
    {
        return RedirectToAction("Test1");
    }

    public ActionResult Test1()
    {
        string Str = Convert.ToString(TempData["T"]);
        TempData.Keep(); // Keep TempData
        return RedirectToAction("Test2");
    }

    public ActionResult Test2()
    {
        string Str = Convert.ToString(TempData["T"]); //OutPut - T
        return View();
    }
}

如果你注意上面的代码,在 RedirectToAction 和读取数据之后数据都不会丢失,原因是,我们使用的是TempData.Keep()。是那个

通过这种方式,您可以让它在其他控制器中持续存在,只要您愿意。

ViewBag/ViewData

Data会持久化到对应的View中

【讨论】:

    【解决方案3】:

    MVC 中的 ViewBag、ViewData、TempData 和视图状态

    http://royalarun.blogspot.in/2013/08/viewbag-viewdata-tempdata-and-view.html

    ASP.NET MVC 为我们提供了三个选项 ViewData、VieBag 和 TempData,用于将数据从控制器传递到视图以及下一个请求。 ViewData 和 ViewBag 几乎相似,而 TempData 执行额外的职责。

    ViewBag 和 ViewData 的相似之处:

    当您从控制器移动到视图时,有助于维护数据。曾经 将数据从控制器传递到相应的视图。短暂的生命意味着 发生重定向时 value 变为 null。这是因为他们的目标 是提供一种在控制器和视图之间进行通信的方式。它的 服务器调用中的一种通信机制。

    ViewBag 和 ViewData 的区别:

    ViewData 是一个对象字典,它派生自 ViewDataDictionary 类,可使用字符串作为键进行访问。查看包 是一个动态属性,它利用了新的动态特性 在 C# 4.0 中。 ViewData 需要对复杂数据类型进行类型转换,并且 检查空值以避免错误。 ViewBag 不需要 复杂数据类型的类型转换。

    ViewBag 和 ViewData 示例:

    public ActionResult Index()
    
    {  
        ViewBag.Name = "Arun Prakash";
        return View();    
    }
    
    public ActionResult Index()  
    {
        ViewData["Name"] = "Arun Prakash";
        return View(); 
    }
    

    在视图中,我们调用如下:

    @ViewBag.Name   
    @ViewData["Name"]
    

    临时数据:

    当您从一个控制器移动到另一个控制器时有助于维护数据 控制器或从一个动作到另一个动作。换句话说,当你 重定向,“临时数据”有助于维护这些重定向之间的数据。 它在内部使用会话变量。 TempData 是一个非常 短暂的实例,你应该只在当前使用它 以及后续的请求

    使用 TempData 可靠工作的唯一情况是重定向时。这是因为重定向会终止当前请求(并向客户端发送 HTTP 状态代码 302 Object Moved),然后在服务器上创建一个新请求以提供重定向视图。

    它需要对复杂数据类型进行类型转换并检查空值以避免错误。

    public ActionResult Index()
    {   
       var model = new Review()  
       {  
          Body = "Start",  
          Rating=5  
       };  
    
        TempData["ModelName"] = model;    
        return RedirectToAction("About");   
    } 
    
    public ActionResult About()       
    {  
        var model= TempData["ModelName"];  
        return View(model);   
    }  
    

    【讨论】:

      【解决方案4】:
      void Keep()
      
      Calling this method with in the current action ensures that all the items in TempData are not removed at the end of the current request.
      
          @model MyProject.Models.EmpModel;
          @{
          Layout = "~/Views/Shared/_Layout.cshtml";
          ViewBag.Title = "About";
          var tempDataEmployeet = TempData["emp"] as Employee; //need typcasting
          TempData.Keep(); // retains all strings values
          } 
      
      void Keep(string key)
      
      Calling this method with in the current action ensures that specific item in TempData is not removed at the end of the current request.
      
          @model MyProject.Models.EmpModel;
          @{
          Layout = "~/Views/Shared/_Layout.cshtml";
          ViewBag.Title = "About";
          var tempDataEmployeet = TempData["emp"] as Employee; //need typcasting
          TempData.Keep("emp"); // retains only "emp" string values
          } 
      

      【讨论】:

        【解决方案5】:

        临时数据 在第一次阅读之前将始终可用,一旦您阅读它,它就不再可用,可以用于传递快速消息也可以查看第一次阅读后将消失的信息。 查看包 它在将数据快速传递给视图时更有用,通常你应该通过模型将所有数据传递给视图,但是在某些情况下,你的模型直接来自映射到数据库之类的实体框架的类 在这种情况下,您无需更改模型以传递新数据,您可以将其粘贴到视图袋中 ViewData 只是 ViewBag 的索引版本,在 MVC3 之前使用过

        【讨论】:

          【解决方案6】:

          viewbag 和 temptdata 的范围也不同。 viewbag 基于第一个视图(不在动作方法之间共享),但 temptdata 可以在动作方法之间共享。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-09-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-09-15
            • 2018-11-23
            相关资源
            最近更新 更多