Wie rufe ich Formularwerte aus HTTPPOST, Wörterbuch oder ab?

111

Ich habe einen MVC-Controller mit dieser Aktionsmethode:

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

Das Formular ist ein nicht triviales Formular mit einem einfachen Textfeld.

Frage

Wie greife ich auf die Parameterwerte zu?

Ich poste nicht aus einer Ansicht, der Beitrag kommt extern. Ich gehe davon aus, dass es eine Sammlung von Schlüssel / Wert-Paaren gibt, auf die ich Zugriff habe.

Ich habe es versucht, Request.Params.Get("simpleTextBox");aber es wird der Fehler "Entschuldigung, bei der Bearbeitung Ihrer Anfrage ist ein Fehler aufgetreten." Zurückgegeben.

Richard
quelle

Antworten:

155

Sie können Ihre Controller-Aktion ein Objekt ausführen lassen, das die Namen der Formulareingaben widerspiegelt, und der Standardmodellordner erstellt dieses Objekt automatisch für Sie:

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

    ... return something ...
}

Ein anderer (offensichtlich hässlicherer) Weg ist:

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

    ... return something ...
}
Darin Dimitrov
quelle
5
Ich möchte nur darauf hinweisen, dass Sie die Sicherung des Compilers in Option 2 verlieren. Wenn sich das Modell ändert, wird der Compiler die Änderung in den zugehörigen Controllern nicht erfassen. Es gibt gute Fälle für Option 2, aber ich würde keine breite Verwendung empfehlen.
Serguei Fedorov
1
Manchmal braucht man hässliches Zeug, es ist gut, eine Wahl zu haben, wenn man bereits weiß, was die besten Praktiken sind
Oscar Ortiz
Warum ist der zweite Weg hässlicher, wenn jemand noch Dot Net lernt?
Gans
3
@Goose, weil es magische Saiten sind. Sie erhalten keine Sicherheit für die Kompilierungszeit. Ihr Code schlägt zur Laufzeit fehl, wenn Sie im Namen der Variablen einen Tippfehler machen. Wenn Sie eine starke Eingabe verwenden, ist der Compiler Ihr Freund.
Darin Dimitrov
@DarinDimitrov macht Sinn. Anders als die Welt, aus der ich komme. Sehr schönes Feature.
Gans
104

Einfach können Sie FormCollectionwie folgt verwenden :

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

Sie können auch eine Klasse verwenden, die mit Formularwerten verknüpft ist, und die asp.net mvc-Engine füllt sie automatisch aus:

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

[HttpPost]
public ActionResult SubmitAction(MyForm form)
{      
  string var1 = form1.Var1;
}
Adeel
quelle
Ich mochte die Klassenlösung, es ist einfach und unkompliziert
Basheer AL-MOMANI
36

Die Antworten sind sehr gut, aber es gibt in der neuesten Version von MVC und .NET einen anderen Weg, den ich wirklich gerne verwende, anstelle der FormCollection- und Request-Schlüssel der "alten Schule".


Stellen Sie sich ein HTML-Snippet vor, das in einem Formular-Tag enthalten ist, das entweder einen AJAX- oder einen FORM-POST ausführt.

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

Ihr Controller analysiert die Formulardaten tatsächlich und versucht, sie Ihnen als Parameter des definierten Typs zu liefern. Ich habe das Kontrollkästchen eingefügt, weil es schwierig ist. Es gibt Text "on" zurück, wenn aktiviert, und null, wenn nicht aktiviert. Die Anforderung ist jedoch, dass diese definierten Variablen vorhanden sein MÜSSEN (es sei denn, nullable (denken Sie daran, obwohl dies stringnullable ist)), andernfalls schlägt die AJAX- oder POST-Rückmeldung fehl.

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

Sie können ein Modell auch ohne Rasiermesser zurückschicken. Ich habe festgestellt, dass dies einige Male benötigt wird.

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

Das HTML-Markup wird einfach ...

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

und Ihr Controller (Razor Engine) fängt die Formularvariable "variableName" ab (Name ist wie Sie möchten, aber halten Sie ihn konsistent) und versucht, ihn aufzubauen und in MyModel umzuwandeln.

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

Wenn ein Controller ein Modell erwartet (in diesem Fall HomeModel), müssen Sie nicht ALLE Felder definieren, da der Parser sie nur auf dem Standardwert belässt, normalerweise NULL. Das Schöne ist, dass Sie verschiedene Modelle im Mark-up kombinieren können und die Post-Back-Analyse so viel wie möglich ausfüllt. Sie müssen kein Modell auf der Seite definieren oder Helfer verwenden.

TIPP: Der Name des Parameters in der Steuerung ist der im HTML-Markup "name =" definierte Name, nicht der Name des Modells, sondern der Name der erwarteten Variablen im!


Die Verwendung List<>ist in ihrem Markup etwas komplexer.

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

Index on List <> MUSS immer nullbasiert und sequentiell sein. 0,1,2,3.

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

Verwendung IEnumerable<>für nicht auf Null basierende und nicht sequentielle Indizes. Wir müssen eine zusätzliche versteckte Eingabe hinzufügen, um dem Ordner zu helfen.

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

Und der Code muss nur IEnumerable verwenden und aufrufen ToList()

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

Es wird empfohlen, pro Seite ein einzelnes Modell oder ein ViewModel (Modell, das andere Modelle enthält, um ein komplexes Ansichtsmodell zu erstellen) zu verwenden. Das vorgeschlagene Mischen und Anpassen kann als schlechte Praxis angesehen werden, aber solange es funktioniert und lesbar ist, ist es nicht schlecht. Es zeigt jedoch die Leistung und Flexibilität des Razor-Motors.

Wenn Sie also etwas Willkürliches eingeben oder einen anderen Wert eines Razor-Helfers überschreiben müssen oder einfach keine eigenen Helfer für ein einzelnes Formular erstellen möchten, das eine ungewöhnliche Kombination von Daten verwendet, können Sie diese Methoden schnell verwenden, um zusätzliche Werte zu akzeptieren Daten.

Piotr Kula
quelle
Die Verwendung der Indexoption ist unklar. Wer auf Gottes grüner Erde hätte gewusst, dass er das benutzt oder dass es überhaupt existiert?! Aber ich bin froh, dass ich diesen Beitrag gefunden habe. Es wird viel Netzwerkverkehr sparen.
Michael Silver
1
Dies funktionierte für mich, aber erst nachdem ich <input type = "hidden" id = "myId"> in @ Html.Hidden ("myId")
geändert hatte
@Piotr - Bitte beheben Sie Ihre Referenzinkonsistenzen mit MyModel und MyHomes. Es verursacht Verwirrung darüber, wie es aktuell ist.
Spencer Sullivan
15

Wenn Sie die Formulardaten direkt von der HTTP-Anfrage ohne Modellbindungen abrufen möchten, FormCollectionkönnen Sie Folgendes verwenden:

[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]);
}
A-Sharabiani
quelle
2
Achtung, dass dies eine schlechte Form sein kann (kein Wortspiel beabsichtigt), aber manchmal möchten Sie nur die Formularwerte und können die Funktionssignatur nicht sauber ändern. Dies ist hier die einzige Lösung, die zu meiner speziellen Situation passt.
Ryan
Wie kann man diese Methode mit diesen statischen Referenzen testen? FormCollection wäre beim Testen weitaus wünschenswerter.
Kees de Wit
@KeesdeWit Wenn Sie den vorherigen Kommentar lesen, ist dies nicht der beste Weg, wird aber manchmal als Problemumgehung verwendet. Zum Unit-Test können Sie das wahrscheinlich verspotten Requestund in die Methode injizieren.
A-Sharabiani