MVC - 使用RedirectToAction()传递数据

59

我想把在MVC用户表单中输入的数据显示到另一个视图中。

该类有如下私有变量:

IList<string> _pagecontent = new List<string>();
以下操作接受一个FormCollection对象,对其进行验证,并将其作为List传递到“Preview”视图中:
[Authorize(Roles = "Admins")]
[ValidateInput(false)]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UpdateContent(FormCollection collection)
{
    if (ModelState.IsValid)
    {
        string PageToInsert = collection["PageToInsert"];
        string PageHeader = collection["PageHeader"];
        string PageBody = collection["PageBody"];

        //validate, excluded...

        _pagecontent.Add(PageToInsert);
        _pagecontent.Add(PageHeader);
        _pagecontent.Add(PageBody);

    }
    return RedirectToAction("Preview", _pagecontent);
}

预览视图具有以下页面指令,用于传递强类型对象列表:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Template.Master" Inherits="System.Web.Mvc.ViewPage<List<string>>" %>

我本以为可以使用Model对象来获取我的数据,但是不幸的是我不能这样做。在下面这行代码中,我遇到了一个“索引超出范围”的异常,提示索引必须是非负数且小于集合的大小:

<% if (Model[0].ToString() == "0") { %>

而且URL上出现了一些奇怪的参数,因为它解析为http://localhost:1894/Admin/Preview?Capacity=4&Count=3

所以我有两个问题:

  1. 当我调用RedirectToAction并传递我的List时,为什么在视图的Model对象中无法访问它?
  2. 如何正确地实现我正在尝试做的事情,即将一组字符串传递给视图以在那里显示?

请查看此链接:http://www.codingfusion.com/Post/Passing-Data-with-RedirectToAction--in-NET-MVC - undefined
8个回答

57

我确实尝试过ViewData,但无法使其正常工作。TempData也是一样,昨晚睡觉前我只是简单地尝试了一下。最重要的是,我真的想避免使用这些字典并使用强类型视图模型对象。 - splatto
1
是的,但是你的视图模型对象——它不会在 HTTP 302 跳转期间保持强类型。你可以将模型放入 TempData 中并进行强制转换。(说实话,当使用 ASP.NET MVC 时,我发现放弃类型控制会更容易些,因为它并不能很好地完成这项工作。) - MichaelGG
1
链接已失效。 - Jamie

14

在使用TempData时要小心。它在单个服务器环境中表现很好,但在云环境中可能无法按预期工作,因为您无法保证请求会命中同一台计算机。这是因为TempData依赖于asp.net会话。但如果您使用其他会话管理器,如SQL或AppFabric Cache,它将正常工作。


8
RedirectAction的第二个参数是routeValues,而不是model。
protected internal RedirectToRouteResult RedirectToAction(string actionName, object routeValues);

尝试使用TempData来处理模型数据。它可以在重定向之间保留数据。


4
使用RedirectToAction的问题在于它返回一个HTTP 302状态码,浏览器会自己发起一个全新的HTTP请求。你可以考虑使用cookie和/或session对象来在请求之间保持数据的持久性。

3

这不起作用是因为RedirectToAction实际上向浏览器发送了Http 302。当浏览器收到此302时,它将向服务器发出新请求以请求新页面。新请求,新的临时变量。

当您尝试保存/编辑/删除某些内容并由于某种原因而拒绝它并必须再次返回旧表单时,您还将面临此问题。

所以,不要使用:

return RedirectToAction("Preview", _pagecontent);

将预览逻辑放在单独的方法中,并直接调用它:
return PreviewLogic(_pagecontent);

你也可以像其他人所说的那样使用TempData[]字典来保存数据以供下一个请求使用,但是这样你将无法避免额外的302次往返服务器。


2

听起来你正在尝试做:

public ActionResult UpdateContent(FormCollection form) {
    ...
    return View("Preview", _pagecontent);
}

请注意,重定向应该是浏览器的“干净状态”(除了认证cookie之类的东西)。您不能告诉浏览器将信息传递给下一个请求,因为下一个请求应该能够独立运行。您只能告诉浏览器下一个要请求的URL是什么。在ASP.NET MVC中,当您将一个参数对象传递给RedirectToAction时,该对象的公共属性将作为查询字符串参数附加到生成的URL中。

我不使用return View()的原因是因为URL将显示调用视图(AddContent),而不是呈现的视图(Preview)。当用户单击“提交”按钮时,它调用了刚刚呈现预览视图的同一个AddContent [Post]操作,因此我无法访问预览[post]操作。 - splatto
你为什么要发布到/MyController/AddContent?为什么不发布到/MyController/Preview? - yfeldblum
我试图让我的AddContent操作发布到Preview,但是当我返回View("Preview", _pagecontent)时,它会呈现Preview,但URL显示为“/Controller/AddContent”。然后,当我单击按钮将其持久化到数据库时,它再次调用Addcontent post操作而不是Preview post操作。 - splatto

0

你不能只是创建两个同名的Action结果,然后将其中一个标记为HttpPost吗?

    public ActionResult UpdateContent(FormCollection preview = null)
    {
        return View(preview);
    }
    [HttpPost]
    public ActionResult UpdateContent(FormCollection collection = null, bool preview = false)
    {
        if (preview)
            return UpdateContent(collection);
        else
            return UpdateContent(null);
    }

-3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接