Comment rediriger vers une page à l'aide du verbe POST?

131

Lorsque vous appelez RedirectToActiondans un contrôleur, il redirige automatiquement à l'aide d'un HTTP GET. Comment lui dire explicitement d'utiliser un HTTP POST?

J'ai une action qui accepte les requêtes GET et POST, et je veux pouvoir RedirectToActionutiliser POST et lui envoyer des valeurs.

Comme ça:

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

Je veux que les valeurs someValueet anotherValuesoient envoyées à l'aide d'un HTTP POST au lieu d'un GET. Est-ce que quelqu'un sait comment faire ça?

Chris Pietschmann
la source
La réponse publiée par jason fonctionnera dans la plupart des scénarios, le seul problème que je vois est qu'elle est sujette aux accidents. c'est-à-dire que l'appel d'une méthode d'action contourne directement tous les filtres appliqués à l'action. Ainsi, au cas où il y aurait une authentification ou une sorte de filtre de compteur appliqué à la méthode d'action, ces données pourraient être perdues. L'appel direct d'une méthode d'action fonctionnera, mais il doit être appliqué avec soin.
amarnath chatterjee

Réponses:

103

HTTP ne prend pas en charge la redirection vers une page à l'aide de POST. Lorsque vous redirigez quelque part, l'en-tête HTTP "Location" indique au navigateur où aller, et le navigateur fait une requête GET pour cette page. Vous devrez probablement simplement écrire le code de votre page pour accepter les requêtes GET ainsi que les requêtes POST.

Eli Courtwright
la source
4
Curieux de savoir pourquoi ma réponse n'est pas acceptée, je pense que ma rhétorique est solide. :) Là encore, je peux être un peu partial à ce sujet ...
Jason Bunting
14
Bien que cette réponse soit fondamentalement correcte, elle n'est pas complète. Voir la réponse de Jason Bunting ci-dessous pour une solution de contournement bien meilleure.
Adrian Grigore
160

Pour votre exemple particulier, je ferais simplement ceci, car vous ne vous souciez évidemment pas que le navigateur reçoive la redirection de toute façon (en acceptant la réponse que vous avez déjà acceptée):

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

Cela fonctionne facilement et il n'y a pas vraiment de choses amusantes en cours - cela vous permet de maintenir le fait que le second n'accepte vraiment que les requêtes HTTP POST (sauf dans ce cas, qui est de toute façon sous votre contrôle) et vous n'avez pas à le faire. utilisez TempData non plus, ce que suggère le lien que vous avez publié dans votre réponse.

J'aimerais savoir ce qui ne va pas avec cela, s'il y a quelque chose. Évidemment, si vous voulez vraiment envoyer une redirection au navigateur, cela ne fonctionnera pas, mais vous devriez alors demander pourquoi vous essayez de convertir cela malgré tout, car cela me semble étrange.

J'espère que cela pourra aider.

Jason Bunting
la source
7
Qui sait pourquoi vous avez été défavorisé. C'est une méthode très utile.
Peter J
2
C'est ainsi que j'ai toujours résolu ce problème. Le vote négatif n'a aucun sens.
Adrian Grigore
39
J'ai voté, bien que je ne sois pas d'accord pour appeler les gens idiots quand vous ne les connaissez pas.
Jim Schubert
3
Je ne suis pas un vote négatif, mais la seule mise en garde à cet égard est que si vous appelez une vue avec un nom différent, ou si les paramètres sont importants, ils sont perdus. La raison en est que l'URL reflétera l'action + les paramètres avant la redirection côté serveur. Cela peut prêter à confusion chez l'utilisateur, en particulier s'il a actualisé la page et s'est ensuite retrouvé sur une page précédente (car l'actualisation utilisait l'ancienne URL). Cette technique est essentiellement très similaire à Server.Transfer d'asp.net, et les mêmes avertissements doivent être exercés.
AaronLS
15
Je n'ai pas contre-voté en soi, mais j'en vois une raison. Cette méthode enfreint la convention de codage définie par le modèle MVC. Cela ne fonctionne que lors de l'appel de la même action. Si l'action est une autre, même sur le même contrôleur, les valeurs de routage sont vissées et la mauvaise vue sera renvoyée. En bref: ne faites pas ça.
erlando
21

Si vous souhaitez transmettre des données entre deux actions lors d'une redirection sans inclure de données dans la chaîne de requête, placez le modèle dans l'objet TempData.

ACTION

TempData["datacontainer"] = modelData;

VUE

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

TempData est censé être une instance de très courte durée, et vous ne devez l'utiliser que pendant les requêtes en cours et les suivantes! Étant donné que TempData fonctionne de cette façon, vous devez savoir avec certitude quelle sera la prochaine demande, et la redirection vers une autre vue est le seul moment où vous pouvez le garantir.

Par conséquent, le seul scénario dans lequel l'utilisation de TempData fonctionnera de manière fiable est lorsque vous effectuez une redirection.

Otto Kanellis
la source
11

essaye celui-là

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
la source
2
Hate it but love it :)
divinci
Un tel hack mais c'était la seule façon de faire ce que je voulais sans violer DRY ou recâbler toute ma configuration! Merci!
jamheadart
6

Je voudrais développer la réponse de Jason Bunting

comme ça

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

Et Eli sera ici pour une idée sur la façon de la rendre variable générique

Peut obtenir tous les types de contrôleur

Yitzhak Weinberg
la source
Vous ne devriez pas créer une instance sur un contrôleur avec new ...()car vous perdrez le RequestContext- si vous êtes déjà dans le même contrôleur, vous n'aurez peut-être pas besoin de créer une nouvelle instance. Sinon, prenez le chemin suivant: SampelController sampleController = DependencyResolver.Current.GetService<SampelController>()alors: sampleController.ControllerContext = new ControllerContext(Request.RequestContext, sampleController);alors vous pouvez return sampleController.Index(2, "text");Juste un indice :)
Matthias Burger