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”.

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 ...
}

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;
}

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.


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]);
}

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.