Como recuperar valores de formulário de HTTPPOST, dicionário ou?


112

Eu tenho um controlador MVC que tem este método de ação:

[HttpPost]
public ActionResult SubmitAction()
{
     // Get Post Params Here
 ... return something ...
}

O formulário é um formulário não trivial com uma caixa de texto simples.

Questão

Como acesso os valores dos parâmetros?

Não estou postando de uma Visualização, a postagem vem externamente. Presumo que haja uma coleção de pares de chave / valor aos quais tenho acesso.

Tentei, Request.Params.Get("simpleTextBox");mas ele retorna o erro "Desculpe, ocorreu um erro ao processar sua solicitação.".

Respostas:


155

Você pode fazer com que a ação do controlador tome um objeto que reflita os nomes de entrada do formulário e o fichário de modelo padrão criará automaticamente este objeto para você:

[HttpPost]
public ActionResult SubmitAction(SomeModel model)
{
    var value1 = model.SimpleProp1;
    var value2 = model.SimpleProp2;
    var value3 = model.ComplexProp1.SimpleProp1;
    ...

    ... return something ...
}

Outra maneira (obviamente mais feia) é:

[HttpPost]
public ActionResult SubmitAction()
{
    var value1 = Request["SimpleProp1"];
    var value2 = Request["SimpleProp2"];
    var value3 = Request["ComplexProp1.SimpleProp1"];
    ...

    ... return something ...
}

5
Gostaria apenas de salientar que você perde o backup do compilador na opção 2. Se o modelo for alterado, o compilador não capturará a alteração nos controladores relacionados. Existem bons casos para a opção 2, mas eu não encorajaria o uso amplo.
Serguei Fedorov

1
Às vezes você precisa de coisas feias, é bom ter uma escolha quando você já sabe quais são as melhores práticas
Oscar Ortiz

Como alguém ainda está aprendendo dot net, por que a segunda forma é mais feia?
Goose

3
@Goose, porque são cordas mágicas. Você não obtém nenhuma segurança de tempo de compilação. Seu código falhará em tempo de execução se você cometer um erro de digitação no nome da variável, enquanto se você estiver usando uma digitação forte, o compilador será seu amigo.
Darin Dimitrov

@DarinDimitrov faz sentido. Diferente do mundo de onde venho. Muito bom recurso.
Goose

104

Simplesmente, você pode usar FormCollectioncomo:

[HttpPost] 
public ActionResult SubmitAction(FormCollection collection)
{
     // Get Post Params Here
 string var1 = collection["var1"];
}

Você também pode usar uma classe, que é mapeada com valores de formulário, e o motor asp.net mvc a preenche automaticamente:

//Defined in another file
class MyForm
{
  public string var1 { get; set; }
}

[HttpPost]
public ActionResult SubmitAction(MyForm form)
{      
  string var1 = form1.Var1;
}

gostei da solução da aula, é fácil e simples
Basheer AL-MOMANI

36

As respostas são muito boas, mas há outra maneira na versão mais recente do MVC e .NET que eu realmente gosto de usar, em vez das chaves FormCollection e Request da "velha escola".


Considere um fragmento de HTML contido em uma tag de formulário que faz um AJAX ou FORM POST.

<input type="hidden"   name="TrackingID" 
<input type="text"     name="FirstName"  id="firstnametext" />
<input type="checkbox" name="IsLegal"  value="Do you accept terms and conditions?" />

Seu controlador irá realmente analisar os dados do formulário e tentar entregá-los a você como parâmetros do tipo definido. Incluí a caixa de seleção porque é complicada. Ele retorna o texto "on" se marcado e nulo se não marcado. O requisito, entretanto, é que essas variáveis ​​definidas DEVEM existir (a menos que sejam anuláveis ​​(lembre-se de que isso stringé anulável)), caso contrário, o AJAX ou POST irá falhar.

[HttpPost]
public ActionResult PostBack(int TrackingID, string FirstName, string IsLegal){
    MyData.SaveRequest(TrackingID,FirstName, IsLegal == null ? false : true);
}

Você também pode postar de volta um modelo sem usar nenhum auxiliar de navalha. Eu descobri que isso é necessário algumas vezes.

public Class HomeModel
{
  public int HouseNumber { get; set; }
  public string StreetAddress { get; set; }
}

A marcação HTML será simplesmente ...

<input type="text" name="variableName.HouseNumber" id="whateverid" >

e seu controlador (Razor Engine) irá interceptar a variável de formulário "variableName" (o nome é como você quiser, mas mantenha-o consistente) e tentará construí-la e lançá-la em MyModel.

[HttpPost]
public ActionResult PostBack(HomeModel variableName){
    postBack.HouseNumber; //The value user entered
    postBack.StreetAddress; //the default value of NULL.
}

Quando um controlador está esperando um Model (neste caso, HomeModel) você não precisa definir TODOS os campos, pois o analisador apenas os deixará no padrão, geralmente NULL. O bom é que você pode misturar e combinar vários modelos no Mark-up e a análise posterior do post preencherá o máximo possível. Você não precisa definir um modelo na página ou usar nenhum auxiliar.

DICA: O nome do parâmetro no controlador é o nome definido na marcação HTML "name =" não o nome do modelo, mas o nome da variável esperada no!


O uso List<>é um pouco mais complexo em sua marcação.

<input type="text" name="variableNameHere[0].HouseNumber" id="id"           value="0">
<input type="text" name="variableNameHere[1].HouseNumber" id="whateverid-x" value="1">
<input type="text" name="variableNameHere[2].HouseNumber"                   value="2">
<input type="text" name="variableNameHere[3].HouseNumber" id="whateverid22" value="3">

O índice na lista <> DEVE ser sempre baseado em zero e sequencial. 0,1,2,3.

[HttpPost]
public ActionResult PostBack(List<HomeModel> variableNameHere){
     int counter = MyHomes.Count()
     foreach(var home in MyHomes)
     { ... }
}

Uso IEnumerable<>de postback de índices não baseados em zero e não sequenciais. Precisamos adicionar uma entrada extra oculta para ajudar o fichário.

<input type="hidden" name="variableNameHere.Index" value="278">
<input type="text" name="variableNameHere[278].HouseNumber" id="id"      value="3">

<input type="hidden" name="variableNameHere.Index" value="99976">
<input type="text" name="variableNameHere[99976].HouseNumber" id="id3"   value="4">

<input type="hidden" name="variableNameHere.Index" value="777">
<input type="text" name="variableNameHere[777].HouseNumber" id="id23"    value="5">

E o código só precisa usar IEnumerable e chamar ToList()

[HttpPost]
public ActionResult PostBack(IEnumerable<MyModel> variableNameHere){
     int counter = variableNameHere.ToList().Count()
     foreach(var home in variableNameHere)
     { ... }
}

Recomenda-se o uso de um único Model ou ViewModel (Modelo contendo outros modelos para criar um modelo de 'Visualização' complexo) por página. Misturar e combinar como proposto pode ser considerado uma prática ruim, mas desde que funcione e seja legível, não é RUIM. No entanto, demonstra a potência e flexibilidade do motor Razor.

Portanto, se você precisar inserir algo arbitrário ou substituir outro valor de um auxiliar do Razor, ou simplesmente não quiser fazer seus próprios auxiliares, para um único formulário que usa alguma combinação incomum de dados, você pode usar rapidamente esses métodos para aceitar dados.


Usar a opção Índice é obscuro. Quem na terra verde de Deus saberia usar isso ou que ela existia ?! Mas, estou feliz por ter encontrado este post. Isso vai economizar uma grande quantidade de tráfego de rede.
Michael Silver

1
Isso funcionou para mim, mas só depois que mudei <input type = "hidden" id = "myId"> para @ Html.Hidden ("myId")
radkan

@Piotr - corrija suas inconsistências de referência com MyModel e MyHomes. Causa confusão como está atualmente.
Spencer Sullivan

15

Se você deseja obter os dados do formulário diretamente da solicitação Http, sem qualquer vinculação de modelo ou FormCollectionvocê pode usar isto:

[HttpPost] 
public ActionResult SubmitAction() {

    // This will return an string array of all keys in the form.
    // NOTE: you specify the keys in form by the name attributes e.g:
    // <input name="this is the key" value="some value" type="test" />
    var keys = Request.Form.AllKeys;

    // This will return the value for the keys.
    var value1 = Request.Form.Get(keys[0]);
    var value2 = Request.Form.Get(keys[1]);
}

2
Cuidado, pois isso pode ser um formato incorreto (sem trocadilhos), mas às vezes você só quer os valores do formulário e não pode alterar a assinatura da função de forma limpa. Esta é a única solução aqui que se adequa à minha situação particular.
Ryan

Como testar a unidade desse método com essas referências estáticas? FormCollection seria muito mais desejável quando se trata de testes.
Kees de Wit

@KeesdeWit se você leu o comentário anterior, esta não é a melhor maneira, mas às vezes use como uma solução alternativa. Para testar a unidade, provavelmente você pode simular o Requeste injetá-lo no método.
A-Sharabiani
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.