views:

5879

answers:

6

What I'm attempting to do is take the data entered into an MVC user form and submit it back to the user in a different view.

I have a private variabled declared in the class:

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

Here is my action that accepts the FormCollection object, validates it, and tries to pass 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);
}

On the Preview view, I have the following Page Directive, which you can see is correct:

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

So as you see I'm passing a strongly typed object List. Now I would expect I could 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 that the index must be non-negative and less than the size of the collection:

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

I also notice that some strange parameters have been added to the url, as it resolves to http://localhost:1894/Admin/Preview?Capacity=4&amp;Count=3

So I have two questions about this.

  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.
+2  A: 

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.

Chad Moran
+10  A: 

Try using TempData. It is like a single-shot session object. You put values you want into TempData, immediately redirect and get them out. There is a good writeup here: http://blogs.teamb.com/craigstuntz/2009/01/23/37947/

MichaelGG
I did try ViewData but couldn't get it working. Same with TempData but I only gave it a brief go before bed last night. The biggest thing is, I really want to avoid these dictionaries and use the strongly typed View Model object
splatto
Yea, but your View Model object -- that's not going to stick around strongly typed over an HTTP 302. You can stick the model into TempData and cast it out. (Honestly, I find it easier to half give up on typing when using ASP.NET MVC, since it simply doesn't do it well.)
MichaelGG
A: 

It looks like you are looking for the UpdateModel command:

Check out ScottGu's blog post on the topic:

Improved UpdateModel and TryUpdateModel methods

David P
+1  A: 

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.

Justice
My reason for not using return View() is because the url will display the calling View (AddContent), not the rendered View (Preview). When the user clicks "submit" button, it calls the same AddContent [Post] action that just rendered the Preview view, so then I cannot hit the Preview [post] action.
splatto
Why are you posting to /MyController/AddContent? Why not post to /MyController/Preview?
Justice
I trying to have my AddContent action post to Preview, but when I return View("Preview", _pagecontent) it renders Preview but the url says "/Controller/AddContent". Then when I click the button to persist to the database, it again calls the Addcontent post action instead of the Preview post action.
splatto
+3  A: 

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.

AndreasN
A: 

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.

andrecarlucci