Comment récupérer des valeurs de formulaire à partir de HTTPPOST, d'un dictionnaire ou?

112

J'ai un contrôleur MVC qui a cette méthode d'action:

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

Le formulaire est un formulaire non trivial avec une simple zone de texte.

Question

Comment accéder aux valeurs des paramètres?

Je ne publie pas à partir d'une vue, le message vient de l'extérieur. Je suppose qu'il existe une collection de paires clé / valeur auxquelles j'ai accès.

J'ai essayé Request.Params.Get("simpleTextBox");mais cela renvoie l'erreur "Désolé, une erreur s'est produite lors du traitement de votre demande.".

Richard
la source

Réponses:

155

Vous pouvez demander à l'action de votre contrôleur de prendre un objet qui refléterait les noms d'entrée du formulaire et le classeur de modèle par défaut créera automatiquement cet objet pour vous:

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

    ... return something ...
}

Une autre façon (évidemment plus laide) est:

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

    ... return something ...
}
Darin Dimitrov
la source
5
Je voudrais juste souligner que vous perdez la sauvegarde du compilateur dans l'option 2. Si le modèle change, le compilateur n'attrapera pas le changement dans les contrôleurs associés. Il existe de bons cas pour l'option 2 mais je n'encouragerais pas une large utilisation.
Serguei Fedorov
1
Parfois, vous avez besoin de trucs laid, c'est bien d'avoir le choix quand vous savez déjà quelles sont les meilleures pratiques
Oscar Ortiz
En tant que personne qui apprend encore dot net, pourquoi la deuxième voie est-elle plus moche?
Goose
3
@Goose, car ce sont des cordes magiques. Vous n'obtenez aucune sécurité lors de la compilation. Votre code échouera à l'exécution si vous faites une faute de frappe dans le nom de la variable alors que si vous utilisez un typage fort, le compilateur sera votre ami.
Darin Dimitrov
@DarinDimitrov a du sens. Différent du monde d'où je viens. Très belle fonctionnalité.
Goose
104

Simplement, vous pouvez utiliser FormCollectioncomme:

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

Vous pouvez également utiliser une classe, qui est mappée avec des valeurs de formulaire, et le moteur asp.net mvc la remplit automatiquement:

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

[HttpPost]
public ActionResult SubmitAction(MyForm form)
{      
  string var1 = form1.Var1;
}
Adeel
la source
J'ai aimé la solution de classe, c'est facile et simple
Basheer AL-MOMANI
36

Les réponses sont très bonnes mais il y a une autre manière dans la dernière version de MVC et .NET que j'aime beaucoup utiliser, au lieu des clés FormCollection et Request "à l'ancienne".


Considérez un extrait de code HTML contenu dans une balise de formulaire qui fait un 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?" />

Votre contrôleur analysera les données du formulaire et essaiera de vous les fournir en tant que paramètres du type défini. J'ai inclus une case à cocher car c'est une question délicate. Il renvoie le texte "on" si coché et nul si non coché. La condition est cependant que ces variables définies DOIVENT exister (à moins que nullable (rappelez-vous bien que ce stringsoit nullable)) sinon le retour AJAX ou POST échouera.

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

Vous pouvez également publier un modèle sans utiliser d'aides de rasoir. J'ai découvert que cela était parfois nécessaire.

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

Le balisage HTML sera simplement ...

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

et votre contrôleur (Razor Engine) interceptera la variable de formulaire "variableName" (le nom est comme vous le souhaitez mais gardez-le cohérent) et essaiera de le construire et de le convertir en MyModel.

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

Lorsqu'un contrôleur attend un modèle (dans ce cas HomeModel), vous n'avez pas à définir TOUS les champs car l'analyseur les laissera par défaut, généralement NULL. La bonne chose est que vous pouvez mélanger et assortir différents modèles sur le Mark-up et l'analyse de post-retour peuplera autant que possible. Vous n'avez pas besoin de définir un modèle sur la page ou d'utiliser des helpers.

ASTUCE: Le nom du paramètre dans le contrôleur est le nom défini dans le balisage HTML "name =" pas le nom du modèle mais le nom de la variable attendue dans le!


L'utilisation List<>est un peu plus complexe dans son balisage.

<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'index sur la liste <> DOIT toujours être basé sur zéro et séquentiel. 0,1,2,3.

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

Utilisation IEnumerable<>pour les index non basés sur zéro et non séquentiels post back. Nous devons ajouter une entrée cachée supplémentaire pour aider le classeur.

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

Et le code doit juste utiliser IEnumerable et appeler ToList()

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

Il est recommandé d'utiliser un seul modèle ou un modèle de vue (modèle contenant d'autres modèles pour créer un modèle de «vue» complexe) par page. Mélanger et assortir comme proposé pourrait être considéré comme une mauvaise pratique, mais tant que cela fonctionne et est lisible, ce n'est pas MAUVAIS. Il démontre cependant la puissance et la flexibilité du moteur Razor.

Donc, si vous avez besoin de supprimer quelque chose d'arbitraire ou de remplacer une autre valeur d'un assistant Razor, ou si vous n'avez tout simplement pas envie de créer vos propres assistants, pour un formulaire unique qui utilise une combinaison inhabituelle de données, vous pouvez rapidement utiliser ces méthodes pour accepter plus Les données.

Piotr Kula
la source
L'utilisation de l'option Index est obscure. Qui sur la terre verte de Dieu aurait su utiliser cela ou même qu'il existait?! Mais je suis content d'avoir trouvé ce post. Cela va économiser beaucoup de trafic réseau.
Michael Silver
1
Cela a fonctionné pour moi, mais seulement après avoir changé <input type = "hidden" id = "myId"> en @ Html.Hidden ("myId")
radkan
@Piotr - veuillez corriger vos incohérences de référence avec MyModel et MyHomes. Cela sème la confusion sur la façon dont il est actuellement.
Spencer Sullivan
15

Si vous souhaitez obtenir les données du formulaire directement à partir de la requête Http, sans aucune liaison de modèle ou FormCollectionvous pouvez utiliser ceci:

[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
la source
2
Attention, cela peut être une mauvaise forme (sans jeu de mots), mais parfois vous voulez juste les valeurs du formulaire et vous ne pouvez pas changer proprement la signature de la fonction. C'est la seule solution ici qui convient à ma situation particulière.
Ryan
Comment tester unitaire cette méthode avec ces références statiques? FormCollection serait bien plus souhaitable pour les tests.
Kees de Wit
@KeesdeWit si vous lisez le commentaire précédent, ce n'est pas la meilleure façon, mais utilisez parfois comme solution de contournement. Pour le test unitaire, vous pouvez probablement vous moquer de Requestet l'injecter dans la méthode.
A-Sharabiani