RedirectToAction (..) с сложным глубоким объектом не работает

Я пытаюсь передать объект из одного действия контроллера другому. Объект, который я просматриваю, выглядит примерно так:

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

Мой контроллер выглядит следующим образом:

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

Метод результата не работает с исключительным исключением, поскольку список PhoneNumbers неожиданно null после вызова действия Result с помощью метода RedirectToAction().

Кто-нибудь видел этот тип поведения раньше?

Приветствия,

Петр

Ответ 1

Я согласен с @Dennis - если вы не хотите, чтобы Url изменился, вам придется подумать о чем-то другом. Причина в том, что RedirectToAction не сериализует данные, он просто выполняет итерации по свойствам объекта объектов маршрута, строя строку запроса, причем ключи являются именами свойств, а значения представляют собой строковое представление значений свойств. Если вы хотите изменить Url, то использование TempData, вероятно, самый простой способ сделать это, хотя вы также можете сохранить элемент в базе данных, передать идентификатор в метод Result и восстановить его оттуда.

Ответ 2

Вам действительно нужно перенаправить на другое действие? RedirectToAction вызывает новый HTTP-запрос, поэтому TempData работает. Не могли бы вы просто вызвать действие Result прямо так?

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

    return Result(person);

}

Изменить. Если ваше приложение не делает больше, чем показано в вопросе, похоже, что вам действительно не нужно действие индекса. Вы можете переместить код, создающий нового человека, в частный метод CreatePerson. В вашем действии Result, если person равно null, вызовите метод CreatePerson. Действие Index может быть полностью устранено, но это потребует изменения ваших маршрутов. Или просто пусть return RedirectToAction("Result", "Dialog"); будет единственной строкой кода в вашем действии Index.

Собственно, после разделения MVC проблем, этот метод CreatePerson должен, вероятно, быть методом внутри вашего кода модели. Контроллер не должен содержать логику создания нового person. Это действительно относится к модели.

Ответ 3

Хотя это старый вопрос, я нашел отличный ответ на него в том, что, по моему мнению, является дублирующим вопросом. Ключ - конструктор RouteValueDictionary.

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

Поскольку у вас есть коллекции, это делает его немного сложнее, но этот другой ответ охватывает это очень хорошо.

Ответ 4

Для всех это действительно нужно вызвать какое-либо действие и вернуть представление с другого контроллера со сложным объектом и не хотеть (или не может) передать объект в TempData. Я использую в своем приложении очень уродливое, но работающее решение:

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

Вдохновленный ответом, найденным здесь: fooobar.com/info/7616/...