Come recuperare i valori del modulo da HTTPPOST, dizionario o?


112

Ho un controller MVC che ha questo metodo di azione:

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

Il modulo è un modulo non banale con una semplice casella di testo.

Domanda

Come accedo ai valori dei parametri?

Non sto postando da una vista, il post arriva esternamente. Presumo che esista una raccolta di coppie chiave / valore a cui ho accesso.

Ho provato Request.Params.Get("simpleTextBox");ma restituisce l'errore "Spiacenti, si è verificato un errore durante l'elaborazione della tua richiesta.".

Risposte:


155

Puoi fare in modo che l'azione del tuo controller prenda un oggetto che rifletta i nomi di input del modulo e il raccoglitore di modelli predefinito creerà automaticamente questo oggetto per te:

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

    ... return something ...
}

Un altro modo (ovviamente più brutto) è:

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

    ... return something ...
}

5
Vorrei solo sottolineare che si perde il backup del compilatore nell'opzione 2. Se il modello cambia, il compilatore non rileverà la modifica nei relativi controller. Ci sono buoni casi per l'opzione 2 ma non ne incoraggerei un ampio utilizzo.
Serguei Fedorov

1
A volte hai bisogno di cose brutte, è bene avere una scelta quando sai già quali sono le migliori pratiche
Oscar Ortiz

Dato che qualcuno sta ancora imparando il dot net, perché il secondo modo è più brutto?
Goose

3
@Goose, perché sono stringhe magiche. Non si ottiene alcuna sicurezza in fase di compilazione. Il tuo codice fallirà in fase di esecuzione se fai un errore di battitura nel nome della variabile, mentre se stai usando una digitazione forte, il compilatore sarà tuo amico.
Darin Dimitrov

@DarinDimitrov ha senso. Diverso dal mondo da cui provengo. Caratteristica molto bella.
Goose

104

Semplicemente, puoi usare FormCollectioncome:

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

Puoi anche usare una classe, che è mappata con i valori del modulo, e il motore asp.net mvc la riempie automaticamente:

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

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


36

Le risposte sono molto buone, ma nell'ultima versione di MVC e .NET c'è un altro modo che mi piace molto usare, invece delle chiavi FormCollection e Request "vecchia scuola".


Considera uno snippet HTML contenuto in un tag form che esegue un AJAX o 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?" />

Il controller analizzerà effettivamente i dati del modulo e proverà a fornirteli come parametri del tipo definito. Ho incluso la casella di controllo perché è complicata. Restituisce il testo "on" se spuntato e null se non spuntato. Il requisito però è che queste variabili definite DEVONO esistere (a meno che nullable (ricorda anche se stringè nullable)) altrimenti l'AJAX o il POST non riusciranno.

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

Puoi anche postare indietro un modello senza utilizzare alcun aiutante di rasoio. Mi sono accorto che questo è necessario alcune volte.

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

Il markup HTML sarà semplicemente ...

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

e il tuo controller (Razor Engine) intercetterà la Form Variable "variableName" (il nome è come preferisci ma mantienilo coerente) e proverà a costruirlo e trasmetterlo a MyModel.

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

Quando un controller si aspetta un modello (in questo caso HomeModel) non è necessario definire TUTTI i campi poiché il parser li lascerà semplicemente al valore predefinito, di solito NULL. La cosa bella è che puoi mescolare e abbinare vari modelli sul mark-up e il post back parse verrà popolato il più possibile. Non è necessario definire un modello sulla pagina o utilizzare gli helper.

SUGGERIMENTO: il nome del parametro nel controller è il nome definito nel markup HTML "name =" non il nome del modello ma il nome della variabile prevista nel!


L'uso List<>è un po 'più complesso nel suo mark-up.

<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">

L'indice su elenco <> DEVE sempre essere in base zero e sequenziale. 0,1,2,3.

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

Utilizzo IEnumerable<>per gli indici non a base zero e non sequenziali postback. Dobbiamo aggiungere un input nascosto extra per aiutare il raccoglitore.

<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 il codice deve solo usare IEnumerable e chiamare ToList()

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

Si consiglia di utilizzare un singolo modello o un ViewModel (il modello che contiene altri modelli per creare un modello "Visualizza" complesso) per pagina. Mescolare e abbinare come proposto potrebbe essere considerato una cattiva pratica, ma fintanto che funziona e sia leggibile non è MALE. Tuttavia, dimostra la potenza e la flessibilità del motore Razor.

Quindi, se devi inserire qualcosa di arbitrario o sovrascrivere un altro valore da un helper Razor, o semplicemente non hai voglia di creare i tuoi helper, per un singolo modulo che utilizza una combinazione insolita di dati, puoi usare rapidamente questi metodi per accettare extra dati.


L'uso dell'opzione Indice è oscuro. Chi sulla terra verde di Dio avrebbe saputo di usarlo o addirittura che esisteva ?! Ma sono contento di aver trovato questo post. Risparmierà una grande quantità di traffico di rete.
Michael Silver

1
Questo ha funzionato per me, ma solo dopo aver cambiato <input type = "hidden" id = "myId"> in @ Html.Hidden ("myId")
radkan

@Piotr - correggi le incongruenze di riferimento con MyModel e MyHomes. Causa confusione come è attualmente.
Spencer Sullivan

15

Se vuoi ottenere i dati del modulo direttamente dalla richiesta Http, senza alcun binding di modello oppure FormCollectionpuoi usare questo:

[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
Attenzione che questa potrebbe essere una cattiva forma (nessun gioco di parole) ma a volte vuoi solo i valori del modulo e non puoi cambiare in modo pulito la firma della funzione. Questa è l'unica soluzione qui che si adatta alla mia situazione particolare.
Ryan

Come eseguire un test unitario di questo metodo con quei riferimenti statici? FormCollection sarebbe molto più desiderabile quando si tratta di test.
Kees de Wit

@KeesdeWit se leggi il commento precedente questo non è il modo migliore, ma a volte lo usi come soluzione alternativa. Per unit test, probabilmente puoi deridere il Requeste iniettarlo nel metodo.
A-Sharabiani
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.