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


74

我正在使用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 });

我将如何实现?


3
这使我绊倒了很长时间-基本上,使用TempData / Session。参见stackoverflow.com/questions/672143/…–
glosrob

Answers:


73

HTTP和重定向

让我们首先回顾一下ASP.NET MVC的工作方式:

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

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

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

传递数据

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

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

正如其他人所建议的

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

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

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

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

因此,现在的问题是,服务器在此期间将文件存储在哪里?好吧,这是您要决定的,最佳选择将取决于您的特定情况。如果长期需要该文档,则可能需要将其存储在磁盘或数据库中。如果它仅包含瞬态信息,则将其保存在Web服务器的内存中,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);
 }

1
谢谢符文。真是的
Devsainii

64

您是否尝试过使用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();
    }
}

1
我是否正确认为TempData在多个负载平衡的服务器上使用是不安全的,除非我还将共享会话缓存放在其下?
GGleGrand 2015年

我仍然认为我们应该避免使用会话,在这种情况下,应使用ViewData。它们没有输入,仅在In-proc会话模式下有效。对于使用State SeverSql Server会话模式的任何负载平衡服务器,ViewData都会丢失。
布莱斯

11

我个人喜欢使用TempData,但我更喜欢传递一个强类型的对象,如ASP.Net-MVC中的在控制器之间传递信息中所述

您应该总是找到一种使之明确和期望的方法。


TempData专门用于将一些简单的数据从一个视图控制器传递到另一个视图控制器,而不会在客户端URL或请求中公开所有数据。它不是理想的,但是比Sessions更有效。它可以很好地处理ViewModel(或简单模型)。并且是一个方便使用的功能。
Piotr Kula 2014年

2
它不处理ViewData,因为ViewData不可序列化,这是无法在进程内运行的会话的要求(Web场)...我非常不喜欢TempData(这是我最好的表达方式)。
Novox 2014年

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();
    }
}

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


2
但在许多情况下,我们希望在中传递一个复杂的模型RedirectToAction
布莱斯

-3

如果需要将数据从一个控制器传递到另一个控制器,则必须按路由值传递数据。由于两者都是不同的请求。如果将数据从一个页面发送至另一页面,则必须使用用户查询字符串(与路由值相同)。

但是您可以做一个技巧:

在您的调用操作中,将被调用操作作为一种简单方法进行调用:

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
 }
}

4
您认为这样值得吗?当您尝试在UpdateConfirmation操作中返回View()时,它会更改路线值并加载正确的视图吗?
KD

绝对是。因为如果调用UpdateConfirmation(),则返回的视图基于“ UpdateConfirmation”操作,即“ / ApplicationPool / UpdateConfirmation”视图。您应该尝试执行此操作。我认为它将起作用。
jishnu saha 2013年

1
不会的 它不会更改路由值字典值,因此MVC会尝试加载首先执行的操作的视图:)
KD

但是从第一个动作开始,您将返回一个包含第二个视图地址的视图,因此它将起作用。
jishnu saha 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.