在不同的控制器动作方法之间传递数据
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 Sever
或Sql 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 - 啥是好方法?