¿Cómo se redirige a una página usando el verbo POST?

131

Cuando usted llama RedirectToAction dentro de un controlador, se redirige automáticamente utilizando un HTTP GET. ¿Cómo le digo explícitamente que use un HTTP POST?

Tengo una acción que acepta solicitudes GET y POST, y quiero poder RedirectToAction usar POST y enviarle algunos valores.

Me gusta esto:

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

Quiero que el someValuey anotherValuelos valores a ser enviado a través de un HTTP POST en lugar de GET. ¿Alguien sabe como hacer esto?

Chris Pietschmann
fuente
La respuesta publicada por Jason funcionará en la mayoría de los escenarios, el único problema que veo es que es propenso a los accidentes. es decir, llamar a un método de acción directamente pasa por alto todos los filtros aplicados a la acción. Por lo tanto, en caso de que haya algún tipo de filtro de autenticación o contador aplicado al método de acción, esos datos podrían perderse. Llamar a un método de acción directamente funcionará, pero debe aplicarse con cuidado.
amarnath chatterjee

Respuestas:

103

HTTP no admite la redirección a una página mediante POST. Cuando redirige a alguna parte, el encabezado "Ubicación" de HTTP le indica al navegador a dónde ir, y el navegador realiza una solicitud GET para esa página. Probablemente tendrá que escribir el código de su página para aceptar solicitudes GET y POST.

Eli Courtwright
fuente
44
Curioso por qué mi respuesta no es aceptada, creo que mi retórica es sólida. :) Por otra parte, puedo ser un poco parcial al respecto ...
Jason Bunting
14
Si bien esta respuesta es básicamente correcta, no está completa. Vea la respuesta de Jason Bunting a continuación para una solución mucho mejor.
Adrian Grigore
160

Para su ejemplo particular, simplemente haría esto, ya que obviamente no le importa que el navegador obtenga la redirección de todos modos (en virtud de aceptar la respuesta que ya ha aceptado):

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

Eso funciona fácilmente y no hay realmente ningún negocio divertido, esto le permite mantener el hecho de que el segundo realmente solo acepta solicitudes HTTP POST (excepto en este caso, que está bajo su control de todos modos) y no tiene que hacerlo use TempData tampoco, que es lo que sugiere el enlace que publicó en su respuesta.

Me encantaría saber qué está "mal" con esto, si hay algo. Obviamente, si realmente desea haber enviado al navegador una redirección, esto no va a funcionar, pero luego debe preguntarse por qué intentaría convertir eso de todos modos, ya que me parece extraño.

Espero que ayude.

Jason Bunting
fuente
77
Quién sabe por qué te rechazaron. Este es un método muy útil.
Peter J
2
Así es como siempre resolví este problema también. Votar abajo esto no tiene sentido.
Adrian Grigore
39
He votado, aunque no estoy de acuerdo con llamar idiotas a las personas cuando no los conoces.
Jim Schubert
3
No soy un votante negativo, pero la única precaución con esto es si llamaras a una vista con un nombre diferente, o si los parámetros son importantes, se pierden. La razón es que la URL reflejará los parámetros de acción + antes de la redirección del lado del servidor. Esto puede generar confusión por parte del usuario, especialmente si actualizaron la página y luego se encontraron en una página anterior (porque la actualización usaba la URL anterior). Esta técnica es esencialmente muy similar a la Server.Transfer de asp.net, y se deben tener las mismas precauciones.
AaronLS
15
No voté en contra per se pero puedo ver razones para hacerlo. Este método viola la convención de codificación establecida por el patrón MVC. Es solamente funciona cuando se llama a la misma acción. Si la acción es otra, incluso en el mismo controlador, los valores de enrutamiento se atornillan y se devuelve la vista incorrecta. En resumen: no hagas esto.
erlando
21

Si desea pasar datos entre dos acciones durante una redirección sin incluir ningún dato en la cadena de consulta, coloque el modelo en el objeto TempData.

ACCIÓN

TempData["datacontainer"] = modelData;

VER

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

TempData está destinado a ser una instancia de muy corta duración, y solo debe usarlo durante las solicitudes actuales y posteriores. Dado que TempData funciona de esta manera, debe saber con certeza cuál será la próxima solicitud, y la redirección a otra vista es la única vez que puede garantizarlo.

Por lo tanto, el único escenario en el que usar TempData funcionará de manera confiable es cuando está redirigiendo.

Otto Kanellis
fuente
11

prueba este

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
fuente
2
Odio pero me encanta :)
divinci
¡Qué truco, pero era la única forma en que podía hacer lo que quería sin violar DRY o volver a cablear toda mi configuración! ¡Gracias!
Jamheadart
6

Me gustaría ampliar la respuesta de Jason Bunting

Me gusta esto

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

Y Eli estará aquí para tener una idea sobre cómo hacer que sea variable genérica

Puede obtener todo tipo de controlador

Itzjak Weinberg
fuente
No debe crear una instancia para un controlador con new ...()porque perderá el RequestContext- si ya está en el mismo controlador, es posible que no necesite crear una nueva instancia. De lo contrario, tome la siguiente manera: SampelController sampleController = DependencyResolver.Current.GetService<SampelController>()luego: sampleController.ControllerContext = new ControllerContext(Request.RequestContext, sampleController);entonces puede return sampleController.Index(2, "text");Solo una pista :)
Matthias Burger