MVC - Передача данных с помощью RedirectToAction()

Я хотел бы взять данные, введенные в пользовательскую форму MVC, и отобразить их в другом представлении.

Класс имеет следующую переменную:

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

Следующее действие принимает объект FormCollection, проверяет его и передает его в представление "Предварительный просмотр" в виде списка:

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

Представление Preview имеет следующую директиву для передачи строго типизированного объекта List:

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

Я бы ожидал, что смогу использовать объект Model для получения моих данных, но, увы, я не могу. В следующей строке я получаю исключение error index out of bounds, указав, что индекс должен быть неотрицательным и меньше, чем размер коллекции:

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

И к URL-адресу добавлены некоторые странные параметры, так как он разрешает http://localhost:1894/Admin/Preview?Capacity=4&Count=3

У меня есть два вопроса:

  • Когда я вызываю RedirectToAction и передаю ему свой список, почему он недоступен в представлении объекта модели?
  • Каков правильный способ делать то, что я пытаюсь сделать, а именно передать коллекцию строк в виде для отображения там?

Ответ 1

Попробуйте использовать TempData. Это похоже на объект сеанса с одним выстрелом. Вы помещаете нужные значения в TempData, сразу перенаправляете и выталкиваете их. Здесь есть хорошая запись: http://blogs.teamb.com/craigstuntz/2009/01/23/37947/

Ответ 2

Будьте осторожны при использовании TempData. Он отлично работает в среде с одним сервером, но в облачной среде он может работать не так, как ожидалось, поскольку вы не можете гарантировать, что запрос попадет на тот же компьютер. Это происходит потому, что TempData полагается на сеанс asp.net. Но если вы используете другой менеджер сеансов, такой как SQL или AppFabric Cache, он будет работать нормально.

Ответ 3

Второй параметр для RedirectAction - это routeValues, а не модель.

protected internal RedirectToRouteResult RedirectToAction(string actionName, object routeValues);

Попробуйте использовать TempData для модели. Его для сохранения данных между переадресациями.

Ответ 4

Проблема с RedirectToAction заключается в том, что он возвращает HTTP 302, и браузер затем переходит к нему и выполняет новый HTTP-запрос. Вы можете захотеть использовать куки файл и/или объект сеанса для сохранения данных между запросами.

Ответ 5

Это не работает, потому что RedirectToAction фактически отправляет Http 302 в браузер. Когда браузер получит этот 302, он выполняет новый запрос на сервер, запрашивающий новую страницу. Новый запрос, новые временные переменные.

Вы также столкнетесь с этой проблемой при попытке сохранить/отредактировать/удалить что-то, и по какой-то причине вы это отрицаете, и вам нужно снова вернуть старую форму.

Итак, вместо:

return RedirectToAction("Preview", _pagecontent);

Поместите логику предварительного просмотра в отдельный метод и просто вызовите его:

return PreviewLogic(_pagecontent);

Вы также можете использовать TempData [] dic для сохранения данных для следующего запроса, как говорили другие, но тогда вы не сможете избежать 302 дополнительных рейсов туда и обратно на сервер.

Ответ 6

Похоже, вы пытаетесь сделать:

public ActionResult UpdateContent(FormCollection form) {
    ...
    return View("Preview", _pagecontent);
}

Обратите внимание, что перенаправление должно быть "чистым списком" для браузера (за исключением таких вещей, как auth cookie). Вы не можете сообщить браузеру передавать информацию по следующему запросу, так как следующий запрос должен иметь возможность самостоятельно. Все, что вам нужно сделать, это указать браузеру, какой URL-адрес запрашивать дальше. В ASP.NET MVC, когда вы передаете аргумент-объект в RedirectToAction, общедоступные свойства этого объекта добавляются в качестве параметров строки запроса в сгенерированный URL.

Ответ 7

Не можете ли вы просто сделать 2 результата действия с тем же именем и отметить 1 из них с помощью HttpPost?

    public ActionResult UpdateContent(FormCollection preview = null)
    {
        return View(preview);
    }
    [HttpPost]
    public ActionResult UpdateContent(FormCollection collection = null, bool preview = false)
    {
        if (preview)
            return UpdateContent(collection);
        else
            return UpdateContent(null);
    }