Jak pobrać wartości formularza z HTTPPOST, słownika lub?

112

Mam kontroler MVC, który ma tę metodę akcji:

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

Formularz to nietrywialny formularz z prostym polem tekstowym.

Pytanie

Jak uzyskać dostęp do wartości parametrów?

Nie publikuję z widoku, wpis jest wysyłany zewnętrznie. Zakładam, że istnieje zbiór par klucz / wartość, do których mam dostęp.

Próbowałem, Request.Params.Get("simpleTextBox");ale zwraca błąd „Przepraszamy, wystąpił błąd podczas przetwarzania żądania”.

Richard
źródło

Odpowiedzi:

155

Możesz sprawić, aby akcja kontrolera przyjęła obiekt, który będzie odzwierciedlał nazwy danych wejściowych formularza, a domyślny spinacz modelu automatycznie utworzy ten obiekt:

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

    ... return something ...
}

Innym (oczywiście brzydszym) sposobem jest:

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

    ... return something ...
}
Darin Dimitrov
źródło
5
Chciałbym tylko zaznaczyć, że tracisz kopię zapasową kompilatora w opcji 2. Jeśli model się zmieni, kompilator nie złapie zmiany w powiązanych kontrolerach. Istnieją dobre przypadki dla opcji 2, ale nie zachęcałbym do szerokiego stosowania.
Serguei Fedorov
1
Czasami potrzebujesz brzydkich rzeczy, dobrze jest mieć wybór, gdy już wiesz, jakie są najlepsze praktyki
Oscar Ortiz
Skoro ktoś wciąż uczy się dot net, dlaczego ten drugi sposób jest brzydszy?
Goose
3
@Goose, bo to magiczne struny. Nie masz żadnego bezpieczeństwa podczas kompilacji. Twój kod nie powiedzie się w czasie wykonywania, jeśli popełnisz literówkę w nazwie zmiennej, podczas gdy jeśli używasz silnego pisania, kompilator będzie twoim przyjacielem.
Darin Dimitrov
@DarinDimitrov ma sens. Inny niż świat, z którego pochodzę. Bardzo fajna funkcja.
Goose
104

Po prostu możesz użyć FormCollection:

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

Możesz również użyć klasy, która jest zamapowana za pomocą wartości formularza, a aparat asp.net mvc automatycznie wypełnia ją:

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

[HttpPost]
public ActionResult SubmitAction(MyForm form)
{      
  string var1 = form1.Var1;
}
Adeel
źródło
Podobało mi się rozwiązanie klasy, które jest łatwe i proste
Basheer AL-MOMANI
36

Odpowiedzi są bardzo dobre, ale w najnowszej wersji MVC i .NET jest inny sposób, z którego bardzo lubię korzystać, zamiast „starej szkoły” kluczy FormCollection i Request.


Rozważmy fragment kodu HTML zawarty w tagu formularza, który wykonuje AJAX lub 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?" />

Twój kontroler faktycznie przeanalizuje dane formularza i spróbuje dostarczyć je jako parametry zdefiniowanego typu. Dodałem pole wyboru, ponieważ jest to trudne. Zwraca tekst „on”, jeśli jest zaznaczony i pusty, jeśli nie jest zaznaczony. Wymóg jest jednak taki, że te zdefiniowane zmienne MUSZĄ istnieć (chyba że dopuszczają wartość null (pamiętaj, że stringdopuszcza wartość null)), w przeciwnym razie AJAX lub POST back nie powiedzie się.

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

Możesz także odesłać model bez korzystania z pomocy maszynki do golenia. Zdałem sobie sprawę, że czasami jest to potrzebne.

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

Znaczniki HTML będą po prostu ...

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

a twój kontroler (Razor Engine) przechwyci zmienną Form Variable „variableName” (nazwa jest taka, jak chcesz, ale zachowaj spójność) i spróbuje ją zbudować i przesłać do MyModel.

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

Kiedy kontroler oczekuje modelu (w tym przypadku HomeModel), nie musisz definiować WSZYSTKICH pól, ponieważ parser po prostu pozostawi je domyślne, zwykle NULL. Fajną rzeczą jest to, że możesz mieszać i dopasowywać różne modele w Mark-up, a analiza zwrotna posta zapełni się jak najwięcej. Nie musisz definiować modelu na stronie ani używać żadnych pomocników.

WSKAZÓWKA: Nazwa parametru w kontrolerze to nazwa zdefiniowana w znaczniku HTML „name =”, a nie nazwa modelu, ale nazwa oczekiwanej zmiennej w!


Używanie List<>jest nieco bardziej złożone pod względem marży.

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

Indeks na liście <> MUSI być zawsze liczony od zera i sekwencyjny. 0,1,2,3.

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

Korzystanie IEnumerable<>z niezerowych i niesekwencyjnych indeksów odesłanych. Musimy dodać dodatkowe ukryte dane wejściowe, aby pomóc segregatorowi.

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

A kod musi po prostu używać IEnumerable i call ToList()

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

Zaleca się użycie pojedynczego modelu lub modelu widoku (model zawierający inne modele do tworzenia złożonego modelu widoku) na stronę. Proponowane mieszanie i dopasowywanie można uznać za złą praktykę, ale dopóki działa i jest czytelne, nie jest ZŁE. Pokazuje jednak moc i elastyczność silnika Razor.

Więc jeśli chcesz wrzucić coś arbitralnego lub zastąpić inną wartość z pomocnika Razor, lub po prostu nie masz ochoty tworzyć własnych pomocników, dla pojedynczego formularza, który używa nietypowej kombinacji danych, możesz szybko użyć tych metod, aby zaakceptować dodatkowe dane.

Piotr Kula
źródło
Korzystanie z opcji Indeks jest niejasne. Kto na Bożej zielonej ziemi wiedział, że to używa, albo że w ogóle istnieje ?! Ale cieszę się, że znalazłem ten post. Zaoszczędzi to dużo ruchu w sieci.
Michael Silver
1
To zadziałało, ale dopiero po zmianie <input type = "hidden" id = "myId"> na @ Html.Hidden ("myId")
radkan
@Piotr - popraw niespójności odniesień z MyModel i MyHomes. To powoduje zamieszanie, jak to jest obecnie.
Spencer Sullivan
15

Jeśli chcesz uzyskać dane formularza bezpośrednio z żądania HTTP, bez żadnych powiązań modelu lub FormCollectionmożesz użyć tego:

[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
źródło
2
Uwaga, może to być zły formularz (gra słów nie jest przeznaczona), ale czasami potrzebujesz tylko wartości formularza i nie możesz jednoznacznie zmienić sygnatury funkcji. To jedyne rozwiązanie, które pasowało do mojej konkretnej sytuacji.
Ryan
Jak przetestować jednostkowo tę metodę z tymi statycznymi odwołaniami? FormCollection byłoby o wiele bardziej pożądane, jeśli chodzi o testowanie.
Kees de Wit
@KeesdeWit, jeśli czytasz poprzedni komentarz, nie jest to najlepszy sposób, ale czasami użyj go jako obejścia. Aby przeprowadzić test jednostkowy, prawdopodobnie można kpić z metody Requesti wstrzyknąć ją do metody.
A-Sharabiani