10

I'm trying to pass an object from one controller action to another. The object that I'm passing around looks more or less like this:

public class Person
{
   public string Name { get; set; }
   public List<PhoneNumber> PhoneNumbers {get; set; }
   public List<Address> Addresses { get; set; }
}

My Controller looks like this:

public class DialogController : Controller
{
    public ActionResult Index()
    {
        // Complex object structure created
        Person person = new Person();
        person.PhoneNumbers = new List();
        person.PhoneNumbers.Add("12341324");

        return RedirectToAction("Result", "Dialog", person);

    }

    public ActionResult Result(Person person)
    {
        string number = person.PhoneNumbers[0].ToString();
        return View();
    }
}

The result method fails with a null pointer exception since the PhoneNumbers list is suddenly null after invoking the Result action with the RedirectToAction() method.

Has anyone seen this type of behavior before?

Cheers,

Peter

DaveRandom
  • 87,921
  • 11
  • 154
  • 174

4 Answers4

9

Do you really need to Redirect to the other action? RedirectToAction causes a brand new http request, which is why TempData works. Couldn't you just call the Result action directly like this?

public ActionResult Index()
{
    // Complex object structure created
    Person person = new Person();
    person.PhoneNumbers = new List();
    person.PhoneNumbers.Add("12341324");

    return Result(person);

}

Edit Unless your app is doing more than what you've shown in the question, it doesn't look like you really need the Index action. You could move the code that creates a new person into a private CreatePerson method. In your Result action if person is null, then call the CreatePerson method. The Index action could be eliminated altogether, but that would require modifying your routes. Or just let return RedirectToAction("Result", "Dialog"); be the only line of code in your Index action.

Actually, following MVC separation of concerns, that CreatePerson method should probably be a method inside your model code. The controller shouldn't need to contain the logic of creating a new Person. That really belongs in the model.

CoderDennis
  • 13,642
  • 9
  • 69
  • 105
  • Hi Dennis, Thanks for the answer. You are totally right about the creation of the Person objects. Thanks! –  Aug 31 '09 at 14:29
5

I agree with @Dennis -- unless you want the Url to change, then you'll have to think of something else. The reason is that RedirectToAction doesn't serialize the data, it simply iterates over the properties in the route values object constructing a query string with the keys being the property names and the values the string representation of the property values. If you want to have the Url change, then using TempData is probably the easiest way to do this, although you could also store the item in the database, pass the id to the Result method, and reconstitute it from there.

tvanfosson
  • 524,688
  • 99
  • 697
  • 795
  • Hi T, I ended up using the TempDaata trick to transfer objects from one action to the other. Thanks for clearing up how RedirectToAction works. That was the real confusing part for me. –  Aug 31 '09 at 14:31
3

Although this is an old question, I found a great answer to it in what I believe is a duplicate question. The key is the RouteValueDictionary constructor.

return RedirectToAction("Result", "Dialog", new RouteValueDictionary(person))

Since you have collections, it makes it a bit tricker, but this other answer covers this very nicely.

Community
  • 1
  • 1
mateuscb
  • 10,150
  • 3
  • 52
  • 76
0

For everyone, that really needs to call some action and return view from another controller with complex object and don't want (or can't) to pass object in TempData. I use in my app very ugly but working solution:

protected ActionResult InternalRedirectToAction(string action, string controller, object model)
{
    var htmlHelper = new HtmlHelper(new ViewContext(
                              ControllerContext,
                              new WebFormView(ControllerContext, "HACK"),
                              new ViewDataDictionary(),
                              TempData, //for sharing TempData between Actions
                              new StringWriter()),
                        new ViewPage());

    var otherViewHtml = htmlHelper.Action(action, controller, model);
    return Content(otherViewHtml.ToString());
}

Inspired by answer found here: https://stackoverflow.com/a/4360019/1341409

Community
  • 1
  • 1
Gh61
  • 9,222
  • 4
  • 28
  • 39