MVC - Passing Data with RedirectToAction()

Viewed 71114

I'd like to take data entered in an MVC user form and display it in a different view.

The class has the following private variable:

IList<string> _pagecontent = new List<string>();

The following action accepts a FormCollection object, validates it, and passes it on to the "Preview" view as a List:

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

The Preview view has the following Page Directive for passing a strongly typed object List:

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

I would expect to be able to use the Model object to get my data, but alas I cannot. At the following line, I get an error index out of bounds exception, stating the index must be non-negative and less than the size of the collection:

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

And some strange parameters have been added to the URL, as it resolves to http://localhost:1894/Admin/Preview?Capacity=4&Count=3

So I have two questions:

  1. When I call RedirectToAction and pass it my List, why is it inaccessible in the view's Model object?
  2. What is the proper way to go about doing what I'm trying to do, namely pass a collection of strings to a view for display there?
8 Answers

The second parameter to RedirectAction is routeValues, not model.

protected internal RedirectToRouteResult RedirectToAction(string actionName, object routeValues);

Try using TempData for the model. Its for persisting data between redirects.

The problem with RedirectToAction is it's returning a HTTP 302 and the browser is then on it's own going and doing a brand new HTTP request. You may want to consider using a cookie and/or session object to persist the data between requests.

This is not working because RedirectToAction is actually sending back a Http 302 to the browser. When the browser receives this 302, it does a new request to the server asking for the new page. New request, new temp variables.

You will also face this problem when you try to save/edit/delete something and for some reason you deny it and you have to return the old form again.

So, instead of:

return RedirectToAction("Preview", _pagecontent);

Put the Preview logic in a separate method and just call it:

return PreviewLogic(_pagecontent);

You can also use the TempData[] dic to persist data for the next request like others have said, but then you will not avoid the 302 additional round trip to the server.

It sounds like you're trying to do:

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

Note that a redirection is supposed to be a "clean slate" for the browser (except for things like the auth cookie). You don't get to tell the browser to pass information along to the next request, since the next request should be able to stand on its own. All you get to do is tell the browser what URL to request next. In ASP.NET MVC, when you pass an arguments-object to RedirectToAction, the public properties of that object are appended as query-string parameters to the generated URL.

Related