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/...