在不同的控制器动作方法之间传递数据

Posted

技术标签:

【中文标题】在不同的控制器动作方法之间传递数据【英文标题】:Passing data between different controller action methods 【发布时间】:2013-03-01 09:29:22 【问题描述】:

我正在使用ASP.NET MVC 4。我正在尝试将数据从一个控制器传递到另一个控制器。我没有做对。我不确定这是否可能?

这是我要从中传递数据的源操作方法:

public class ServerController : Controller

     [HttpPost]
     public ActionResult ApplicationPoolsUpdate(ServiceViewModel viewModel)
     
          XDocument updatedResultsDocument = myService.UpdateApplicationPools();

          // Redirect to ApplicationPool controller and pass
          // updatedResultsDocument to be used in UpdateConfirmation action method
     

我需要将它传递给这个控制器中的这个动作方法:

public class ApplicationPoolController : Controller

     public ActionResult UpdateConfirmation(XDocument xDocument)
     
          // Will add implementation code

          return View();
     

我在ApplicationPoolsUpdate 操作方法中尝试了以下方法,但它不起作用:

return RedirectToAction("UpdateConfirmation", "ApplicationPool", new  xDocument = updatedResultsDocument );

return RedirectToAction("UpdateConfirmation", new  controller = "ApplicationPool", xDocument = updatedResultsDocument );

我将如何实现这一目标?

【问题讨论】:

这让我很困惑 - 基本上,使用 TempData/Session。见***.com/questions/672143/… 【参考方案1】:

HTTP 和重定向

让我们先回顾一下 ASP.NET MVC 的工作原理:

    当一个 HTTP 请求进来时,它与一组路由匹配。如果路由匹配请求,则调用该路由对应的控制器动作。 在调用操作方法之前,ASP.NET MVC 执行模型绑定。模型绑定是将 HTTP 请求的内容(基本上只是文本)映射到您的操作方法的强类型参数的过程

让我们也提醒自己什么是重定向:

HTTP 重定向是网络服务器可以发送给客户端的响应,告诉客户端在不同的 URL 下查找请求的内容。新 URL 包含在 Web 服务器返回给客户端的 Location 标头中。在 ASP.NET MVC 中,您通过从操作返回 RedirectResult 来执行 HTTP 重定向。

传递数据

如果您只是传递字符串和/或整数等简单值,则可以将它们作为查询参数传递到 URL 中的 Location 标头中。如果你使用类似的东西会发生这种情况

return RedirectToAction("ActionName", "Controller", new  arg = updatedResultsDocument );

正如其他人建议的那样

这不起作用的原因是XDocument 是一个可能非常复杂的对象。 ASP.NET MVC 框架没有直接的方法将文档序列化为适合 URL 的内容,然后将模型从 URL 值绑定回您的 XDocument 操作参数。

一般来说,将文档传递给客户端以便客户端在下一次请求时将其传递回服务器,这是一个非常脆弱的过程:它需要各种序列化和反序列化,而且各种事情都可以出问题。如果文档很大,也可能会浪费大量带宽,并可能严重影响应用程序的性能。

相反,您要做的是将文档保留在服务器上并将标识符传递回客户端。然后客户端将标识符与下一个请求一起传递,服务器使用此标识符检索文档。

存储数据以便在下一个请求时检索

那么,现在的问题是,服务器同时将文档存储在哪里?好吧,这由您决定,最佳选择将取决于您的特定情况。如果该文档需要长期可用,您可能希望将其存储在磁盘或数据库中。如果它只包含临时信息,则将其保存在网络服务器的内存中、ASP.NET 缓存中或Session(或TempData,与最后的Session 大致相同)可能是正确的解决方案。无论哪种方式,您都可以将文档存储在允许您稍后检索文档的密钥下:

int documentId = _myDocumentRepository.Save(updatedResultsDocument);

然后您将该密钥返回给客户端:

return RedirectToAction("UpdateConfirmation", "ApplicationPoolController ", new  id = documentId );

当您要检索文档时,您只需根据密钥获取它:

 public ActionResult UpdateConfirmation(int id)
 
      XDocument doc = _myDocumentRepository.GetById(id);

      ConfirmationModel model = new ConfirmationModel(doc);

      return View(model);
 

【讨论】:

谢谢符文。太棒了。【参考方案2】:

您尝试过使用ASP.NET MVC TempData 吗?

ASP.NET MVC TempData 字典用于在控制器操作之间共享数据。 TempData 的值一直持续到它被读取或当前用户的会话超时。在 TempData 中持久化数据在重定向等场景中很有用,当需要值超出单个请求时。

代码是这样的:

[HttpPost]
public ActionResult ApplicationPoolsUpdate(ServiceViewModel viewModel)

    XDocument updatedResultsDocument = myService.UpdateApplicationPools();
    TempData["doc"] = updatedResultsDocument;
    return RedirectToAction("UpdateConfirmation");

在 ApplicationPoolController 中:

public ActionResult UpdateConfirmation()

    if (TempData["doc"] != null)
    
        XDocument updatedResultsDocument = (XDocument) TempData["doc"];
            ...
        return View();
    

【讨论】:

我是否更正了 TempData 不安全地用于多个负载平衡的服务器,除非我还在它下面放置一个共享会话缓存? 我仍然认为我们应该尽量避免使用会话,在这种情况下是 ViewData。它们没有输入,仅在In-proc 会话模式下工作。对于任何使用State SeverSql Server 会话模式的负载平衡服务器,ViewData 都会丢失。【参考方案3】:

我个人喜欢使用 TempData,但我更喜欢传递强类型对象,如 Passing Information Between Controllers in ASP.Net-MVC 中所述。

您应该始终找到一种方法使其明确且符合预期。

【讨论】:

TempData 旨在将一些简单的数据从一个视图控制器传递到另一个视图控制器,而不会暴露客户端 URL 或请求中的所有数据。它并不理想,但比 Sessions 更有效。它可以很好地处理 ViewModel(或简单模型)。并且是一个方便使用的功能。 它不处理 ViewData 因为 ViewData 不可序列化,这是不能在进程中运行的会话的要求(网络农场)......我非常不喜欢 TempData(是最好的方式我可以说)。【参考方案4】:

我更喜欢用这个而不是TempData

public class Home1Controller : Controller 

    [HttpPost]
    public ActionResult CheckBox(string date)
    
        return RedirectToAction("ActionName", "Home2", new  Date =date );
    

另一个controller Action

public class Home2Controller : Controller 

    [HttpPost]
    Public ActionResult ActionName(string Date)
    
       // do whatever with Date
       return View();
    

为时已晚,但我希望将来对任何人有所帮助

【讨论】:

但在很多情况下,我们希望在RedirectToAction中传递一个复杂的模型。【参考方案5】:

如果您需要将数据从一个控制器传递到另一个控制器,则必须通过路由值传递数据。因为两者是不同的请求。如果您将数据从一个页面发送到另一个页面,那么您必须用户查询字符串(与路由值相同) .

但你可以做一个技巧:

在你的调用动作中调用被调用动作作为一个简单的方法:

public class ServerController : Controller

 [HttpPost]
 public ActionResult ApplicationPoolsUpdate(ServiceViewModel viewModel)
 
      XDocument updatedResultsDocument = myService.UpdateApplicationPools();
      ApplicationPoolController pool=new ApplicationPoolController(); //make an object of ApplicationPoolController class.

      return pool.UpdateConfirmation(updatedResultsDocument); // call the ActionMethod you want as a simple method and pass the model as an argument.
      // Redirect to ApplicationPool controller and pass
      // updatedResultsDocument to be used in UpdateConfirmation action method
 

【讨论】:

你觉得这样做值得吗?当您尝试在 UpdateConfirmation 操作中返回 View() 时,它会更改路由值并加载正确的视图吗? 是挑衅。因为如果您调用 UpdateConfirmation(),则返回的视图基于“UpdateConfirmation”操作,即“/ApplicationPool/UpdateConfirmation”视图。你应该试试这个。我认为它会工作。 不会的。它不会更改路由值字典值,因此 MVC 将尝试为首先执行的操作加载视图 :) 但是从第一个动作你返回一个包含第二个视图地址的视图。所以它会起作用。

以上是关于在不同的控制器动作方法之间传递数据的主要内容,如果未能解决你的问题,请参考以下文章

在 RAILS 中将模型从一个控制器动作传递到另一个控制器动作的替代方法

在 ASP.net MVC 4 中将类对象从一个控制器动作传递到不同的控制器动作

在视图控制器之间传递数据 - iOS Xcode - 啥是好方法?

在视图控制器之间移动和传递数据的正确方法

如何在 PageViewController 和 ViewController 之间传递数据?

SpriteKit:在场景之间传递数据