2

I have this actionresult method:

public ActionResult MenuItemCreated(MenuItem item)
{
    return View(item);
}

And this is my view:

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

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    MenuItemCreated
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <h2>MenuItemCreated</h2>

    <%: Model.Caption %> is created succesfully
</asp:Content>

What I see on the page is correct (test is created successfully). But my querystring looks like this:

http://localhost:62602/Admin/MenuItemCreated/2?Caption=test&Link=%2Fclient

EDIT: The ActionResult is called from this method:

public ActionResult CreateMenuItem(FormCollection fc)
{
    MenuItem menuItem = CreateMenuItemFrom(fc);
    SaveMenuItem(menuItem);

    return RedirectToAction("MenuItemCreated", menuItem);
}

EDIT II:

Corresponding view:

<% using (Html.BeginForm("CreateMenuItem","Admin",FormMethod.Post)) {%>
    <%: Html.ValidationSummary(true) %>

    <fieldset>
        <legend>Fields</legend>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Caption) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Caption) %>
            <%: Html.ValidationMessageFor(model => model.Caption) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Link) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Link) %>
            <%: Html.ValidationMessageFor(model => model.Link) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.ParentId) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.ParentId) %>
            <%: Html.ValidationMessageFor(model => model.ParentId) %>
        </div>

        <p>
            <input type="submit" value="Create MenuItem" />
        </p>
    </fieldset>

<% } %>

Why is this? I don't want the querystring to be shown.

1
  • How are you calling this action? I can't see any ActionLink or form in the markup you posted. Commented Apr 1, 2011 at 8:45

5 Answers 5

7

The problem is the following line:

return RedirectToAction("MenuItemCreated", menuItem);

You cannot pass complex objects like this when you perform a redirect. Only simple scalar properties:

return RedirectToAction("MenuItemCreated", new {
    id = menuItem.Id
});

and then inside the action you are redirecting to fetch the corresponding menu item model given the id:

public ActionResult MenuItemCreated(int id)
{
    var menuItem = _someRepository.GetMenuItem(id);
    ...
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thnx I've got it working. One more question. First i tried this: return RedirectToAction("MenuItemCreated", menuItem.Id); But this results in a big exception. When I tried it your way: return RedirectToAction("MenuItemCreated", new { id = menuItem.Id}); it works. What is the difference?
@Martijn, the difference is that the RedirectToAction method expects an anonymous object as second argument. Then the properties of this anonymous object will be sent as query string/route parameters.
Why isn't it possible to use a custom object? Why not use a custom object? They both result in the same value, right? The value is always the id of the newly created menu item.
@Martijn, here's how the RedirectToAction method works: it takes the second argument and lists all its properties and then sends a 302 header to the client with a Location built with those parameters as query string. Then the client simply issues another GET request to fetch the target resource from the server passing everything in the query string.
Thank you. It is not completely clear to me, but I am new to MVC. I think I understand it better in a while :) Do you have/know a url where these kind of subjects are explained?
1

Since RedirectToAction makes a loop through the browser, it needs to pass the information you specified on the URL.

You can pass the data to "MenuItemCreated" via TempData. Using TempData, your object does not go through the browser.

But MenuItemCreated needs to know that the data is expected via TempData, and not via arguments/querystring.

public ActionResult CreateMenuItem(FormCollection fc){
    MenuItem menuItem = CreateMenuItemFrom(fc);
    SaveMenuItem(menuItem); 
    TempData["menuitem"] = menuitem;
    return RedirectToAction("MenuItemCreated");
}

public ActionResult MenuItemCreated(){
    MenuItem menuItem = TempData["menuitem"] as MenuItem;
    // ....
}

Note: This makes passing the parameter from one action to another very obscure.

You could also return the View "MenuItemCreated" from from "CreateMenuItem" like this:

public ActionResult CreateMenuItem(FormCollection fc){
    MenuItem menuItem = CreateMenuItemFrom(fc);
    SaveMenuItem(menuItem); 
    return View("MenuItemCreated", menuitem);
}

The URL does not change into "MenuItemCreated", but the contents of the view MenuItemCreated is rendered.

6 Comments

So, what happens is, all the properties are send by the querystring? Why is this, why isnt it possible to pass (custom) objects this way?
Because a RedirectToAction, sends a command to the browser to redirect to another url.
I would recommend against using TempData for transporting complex objects between redirects because if the user hits F5 to refresh on the redirected page it will crash because TempData will no longer have the object. Use TempData only for transporting some simple confirmation messages like thanks for submitting, ...
Thank you for pointing me at the alternative way: return View("MenuItemCreated", menuitem);
@Darin, you can protect yourself against that, by placing the object back into the TempData (in the target Action).
|
0

You'll have to set the post property on the actionresult method

[HttpPost()]
public ActionResult MenuItemCreated(MenuItem item)
{
    return View(item);
}

1 Comment

This is what Swaff suggested. I've tried this with no lock. See my comment @Swaff.
0

Try this:

public ActionResult MenuItemCreated(MenuItem item)
{
    ViewData.Model = item;
    return View();
}

1 Comment

No luck, I still get the querystring
0

Try this:

public ActionResult CreateMenuItem(FormCollection fc)
{
    MenuItem menuItem = CreateMenuItemFrom(fc);
    SaveMenuItem(menuItem);

    // tell this action method which view to render
    return View("MenuItemCreated", menuItem);
}

public ActionResult MenuItemCreated(MenuItem item)
{
    return View(item);
}

3 Comments

When I do this, I get this error: The resource cannot be found. Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly. Requested URL: /Admin/MenuItemCreated/3
The request to /Admin/MenuItemCreated/3 will resolve to an expected Action method of MenuItemCreated(int id), can you post the form code that is called this method
I've updated my question with the method that calls MenuItemCreated

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.