Como você redireciona para uma página usando o verbo POST?

131

Quando você chama RedirectToActiondentro de um controlador, ele redireciona automaticamente usando um HTTP GET. Como eu digo explicitamente para usar um HTTP POST?

Tenho uma ação que aceita solicitações GET e POST e desejo poder RedirectToActionusar o POST e enviar alguns valores.

Como isso:

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

Eu quero o someValuee anotherValuevalores a ser enviado com um HTTP POST em vez de um GET. Alguém sabe como fazer isso?

Chris Pietschmann
fonte
A resposta postada por jason funcionará na maioria dos cenários, o único problema que vejo é que é propenso a acidentes. ou seja, chamar um método de ação ignora diretamente todos os filtros aplicados à ação. Portanto, se houver algum tipo de filtro de autenticação ou contador aplicado ao método de ação, esses dados poderão ser perdidos. Chamar um método de ação diretamente funcionará, mas deve ser aplicado com cuidado.
htanramA Chatterjee

Respostas:

103

O HTTP não suporta o redirecionamento para uma página usando o POST. Quando você redireciona para algum lugar, o cabeçalho HTTP "Location" indica ao navegador para onde ir e o navegador faz uma solicitação GET para essa página. Você provavelmente precisará apenas escrever o código da sua página para aceitar solicitações GET e POST.

Eli Courtwright
fonte
4
Curioso por minha resposta não ser aceita, acho que minha retórica é sólida. :) Então, novamente, eu posso ser um pouco tendenciosa sobre isso ...
Jason Bunting
14
Embora essa resposta esteja basicamente correta, ela não está completa. Veja a resposta de Jason Bunting abaixo para uma solução muito melhor.
Adrian Grigore
160

Para o seu exemplo em particular, eu faria isso, já que você obviamente não se importa em ter o navegador para obter o redirecionamento de qualquer maneira (em virtude de aceitar a resposta que você já aceitou):

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

Isso funciona facilmente e não há nenhum negócio engraçado realmente acontecendo - isso permite que você mantenha o fato de que o segundo realmente só aceita solicitações HTTP POST (exceto neste caso, que está sob seu controle de qualquer maneira) e você não precisa use TempData, que é o que o link que você postou na sua resposta está sugerindo.

Eu adoraria saber o que está "errado" com isso, se houver alguma coisa. Obviamente, se você realmente deseja enviar para o navegador um redirecionamento, isso não vai funcionar, mas você deve perguntar por que estaria tentando convertê-lo independentemente, pois isso me parece estranho.

Espero que ajude.

Jason Bunting
fonte
7
Quem sabe por que você foi derrotado. Este é um método muito útil.
Peter J
2
Foi assim que eu sempre resolvi esse problema também. Voto negativo não faz sentido.
Adrian Grigore
39
Votei, embora não concorde em chamar pessoas idiotas quando você não as conhece.
Jim Schubert
3
Eu não sou um defensor negativo, mas o único cuidado com isso é se você chamar uma exibição com um nome diferente ou se os parâmetros forem importantes, eles serão perdidos. O motivo é que o URL refletirá os parâmetros action + antes do redirecionamento do servidor. Isso pode causar confusão pelo usuário, especialmente se ele atualizou a página e se encontrou em uma página anterior (porque a atualização usava o URL antigo). Essa técnica é essencialmente muito semelhante à Server.Transfer do asp.net, e os mesmos cuidados devem ser tomados.
AaronLS
15
Eu não votei em si, mas posso ver o motivo. Este método viola a convenção de codificação configurada pelo padrão MVC. Funciona apenas ao chamar a mesma ação. Se a ação for outra, mesmo no mesmo controlador, os valores de roteamento serão parafusados ​​e a visão errada será retornada. Resumindo: não faça isso.
erlando 24/09/12
21

Se você deseja passar dados entre duas ações durante um redirecionamento sem incluir nenhum dado na cadeia de consulta, coloque o modelo no objeto TempData.

AÇAO

TempData["datacontainer"] = modelData;

VISÃO

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

TempData é uma instância de vida muito curta, e você deve usá-lo apenas durante as solicitações atuais e as subsequentes! Como o TempData funciona dessa maneira, você precisa saber com certeza qual será a próxima solicitação e o redirecionamento para outra visualização é a única vez que você pode garantir isso.

Portanto, o único cenário em que o uso do TempData funcionará de maneira confiável é quando você está redirecionando.

Otto Kanellis
fonte
11

tente 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
fonte
2
Odiá-lo, mas amá-lo :)
divinci
Um hack, mas foi a única maneira de fazer o que queria sem violar o DRY ou religar toda a instalação! Obrigado!
jamheadart
6

Gostaria de expandir a resposta de Jason Bunting

como isso

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

E Eli estará aqui para ter uma ideia de como torná-la variável genérica

Pode obter todos os tipos de controlador

Yitzhak Weinberg
fonte
Você não deve criar uma instância para um controlador new ...()porque perderá o RequestContext- se você já estiver no mesmo controlador, poderá não ser necessário criar uma nova instância. Caso contrário, siga o seguinte caminho: SampelController sampleController = DependencyResolver.Current.GetService<SampelController>()then: sampleController.ControllerContext = new ControllerContext(Request.RequestContext, sampleController);then you can return sampleController.Index(2, "text");Just a hint :)
Matthias Burger