Как выполнить перенаправление на страницу с помощью команды POST?

131

Когда вы вызываете RedirectToActionвнутри контроллера, он автоматически перенаправляет с помощью HTTP GET. Как я могу явно указать ему использовать HTTP POST?

У меня есть действие, которое принимает запросы GET и POST, и я хочу иметь возможность RedirectToActionиспользовать POST и отправлять ему некоторые значения.

Как это:

this.RedirectToAction(
    "actionname",
    new RouteValueDictionary(new { someValue = 2, anotherValue = "text" })
);

Я хочу , чтобы someValueи anotherValueзначения , которые будут отправлены с помощью HTTP POST вместо GET. Кто-нибудь знает как это сделать?

Крис Питчманн
источник
Публикация ответа Джейсона будет работать в большинстве сценариев, единственная проблема, которую я вижу, заключается в том, что она подвержена авариям. т.е. вызов метода действия напрямую обходит все фильтры, применяемые к действию. Таким образом, если к методу действия применяется какой-либо фильтр аутентификации или счетчика, эти данные могут быть потеряны. Вызов метода действия напрямую будет работать, но его следует применять осторожно.
amarnath chatterjee

Ответы:

103

HTTP не поддерживает перенаправление на страницу с помощью POST. Когда вы куда-то перенаправляете, HTTP-заголовок «Location» сообщает браузеру, куда идти, и браузер делает GET-запрос для этой страницы. Вероятно, вам придется просто написать код для своей страницы, чтобы принимать запросы GET, а также запросы POST.

Эли Кортрайт
источник
4
Любопытно, почему мой ответ не принимается, но я думаю, что моя риторика верна. :) С другой стороны, я могу быть немного предвзятым по этому поводу ...
Джейсон Бантинг,
14
Хотя этот ответ в основном правильный, он не является полным. См. Ответ Джейсона Бантинга ниже для гораздо лучшего обходного пути.
Адриан Григоре
160

В вашем конкретном примере я бы просто сделал это, поскольку вы, очевидно, не заботитесь о том, чтобы браузер все равно получил перенаправление (в силу принятия ответа, который вы уже приняли):

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Index() {
   // obviously these values might come from somewhere non-trivial
   return Index(2, "text");
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(int someValue, string anotherValue) {
   // would probably do something non-trivial here with the param values
   return View();
}

Это работает легко, и на самом деле нет никакого забавного бизнеса - это позволяет вам поддерживать тот факт, что второй действительно принимает только запросы HTTP POST (за исключением этого случая, который в любом случае находится под вашим контролем), и вам не нужно также используйте TempData, что предлагает ссылка, которую вы разместили в своем ответе.

Я хотел бы знать, что в этом "не так", если есть что-нибудь. Очевидно, что если вы действительно хотите отправить в браузер перенаправление, это не сработает, но тогда вы должны спросить, почему вы пытаетесь преобразовать это в любом случае, поскольку мне это кажется странным.

Надеюсь, это поможет.

Джейсон Бантинг
источник
7
Кто знает, почему вам отказали. Это очень полезный метод.
Peter J
2
Так я и эту проблему всегда решал. Голосование против этого не имеет смысла.
Адриан Григоре
39
Я проголосовал за, хотя не согласен называть людей идиотами, если вы их не знаете.
Джим Шуберт
3
Я не сторонник отрицательных голосов, но здесь есть одно предостережение: если вы вызываете представление с другим именем или если параметры важны, они теряются. Причина в том, что URL-адрес будет отражать параметры действия + перед перенаправлением на стороне сервера. Это может ввести пользователя в заблуждение, особенно если они обновили страницу, а затем оказались на предыдущей странице (поскольку при обновлении использовался старый URL). Этот метод очень похож на Server.Transfer asp.net, и следует соблюдать те же меры предосторожности.
AaronLS
15
Я не голосовал против, но вижу причину. Этот метод нарушает соглашение о кодировании, установленное шаблоном MVC. Это только работает при вызове же действия. Если действие является другим, даже на том же контроллере, значения маршрутизации завинчиваются и будет возвращено неправильное представление. Вкратце: не делайте этого.
erlando
21

Если вы хотите передавать данные между двумя действиями во время перенаправления без включения каких-либо данных в строку запроса, поместите модель в объект TempData.

ДЕЙСТВИЯ

TempData["datacontainer"] = modelData;

ПОСМОТРЕТЬ

var modelData= TempData["datacontainer"] as ModelDataType; 

TempData предназначена для очень недолговечного экземпляра, и вы должны использовать его только во время текущего и последующих запросов! Поскольку TempData работает таким образом, вам нужно точно знать, каким будет следующий запрос, и перенаправление на другое представление - единственный раз, когда вы можете гарантировать это.

Следовательно, единственный сценарий, в котором использование TempData будет надежно работать, - это перенаправление.

Отто Канеллис
источник
11

Попробуй это

return Content("<form action='actionname' id='frmTest' method='post'><input type='hidden' name='someValue' value='" + someValue + "' /><input type='hidden' name='anotherValue' value='" + anotherValue + "' /></form><script>document.getElementById('frmTest').submit();</script>");
Vicky
источник
2
Ненавижу, но люблю :)
divinci
Такой взлом, но это был единственный способ сделать то, что я хотел, не нарушая DRY и не переделывая всю мою установку! Спасибо!
jamheadart
6

Я хотел бы расширить ответ Джейсона Бантинга

как это

ActionResult action = new SampelController().Index(2, "text");
return action;

И Эли будет здесь, чтобы получить представление о том, как сделать его общей переменной.

Можно получить все типы контроллеров

Ицхак Вайнберг
источник
Вы не должны создавать экземпляр для контроллера с, new ...()потому что вы потеряете RequestContext- если вы уже находитесь в том же контроллере, вам может не понадобиться создавать новый экземпляр. В противном случае используйте следующий способ: SampelController sampleController = DependencyResolver.Current.GetService<SampelController>()затем: sampleController.ControllerContext = new ControllerContext(Request.RequestContext, sampleController);тогда вы можете return sampleController.Index(2, "text");Просто подсказка :)
Маттиас Бургер