web-dev-qa-db-fra.com

Y a-t-il une bonne raison d'utiliser FormCollection au lieu de ViewModel?

J'ai hérité d'une base de code écrite en ASP.Net MVC 4. Chaque méthode de publication prend un FormCollection. Mis à part la gêne d'avoir à accéder aux valeurs via des chaînes entre guillemets, cela entraîne également des inconvénients tels que l'impossibilité d'utiliser des choses comme ModelState.IsValid, ou [AllowHtml] attributs sur mes propriétés ViewModel. En fait, ils ont créé des classes ViewModel pour chacune de leurs vues (bien qu'ils ne soient à peu près que des wrappers directs autour des classes de modèle Entity Framework réelles), mais ils ne sont utilisés que pour les méthodes GET.

Y a-t-il quelque chose qui me manque dans FormCollection qui donne une raison pour laquelle cela a peut-être été une bonne idée? Il ne semble avoir que des inconvénients. J'aimerais passer en revue et "corriger" en utilisant ViewModels à la place. Cela prendrait beaucoup de travail car les ViewModels ont des propriétés qui sont des interfaces et non des classes concrètes, ce qui signifie soit écrire un classeur personnalisé, soit changer les ViewModels.

Mais peut-être que quelque chose me manque où il est logique d'utiliser FormCollection?

43
GendoIkari

Y a-t-il une bonne raison d'utiliser FormCollection au lieu de ViewModel?

Non, j'ai les problèmes suivants.

Problème - 1

Si FormCollection est utilisé ... Il sera obligatoire de Type Cast les Primitive Type Valeurs non nécessairement parce qu'en obtenant l'entrée d'un index spécifique du System.Collections.Specialized.NameValueCollection, la valeur renvoyée est de type String. Cette situation ne se produira pas dans le cas de Strongly Typed View-Models.

Problème - 2

Lorsque vous soumettez le formulaire et accédez à Post Méthode d'action et View-Model comme le paramètre existe dans la méthode Action, vous avez la possibilité de vous renvoyer les valeurs publiées View. Sinon, réécrivez le code pour le renvoyer via TempData/ViewData/ViewBag

enter image description here

Les View-Models sont des classes normales, créées pour lier des données aux vues

Problème -

Nous avons des annotations de données qui peuvent être implémentées dans View Model ou Custom Validations.

enter image description here

ASP.Net MVC simplifie les validations de modèle à l'aide de l'annotation des données. Les annotations de données sont des attributs qui sont appliqués aux propriétés. Nous pouvons créer un attribut de validation personnalisé en héritant de la classe d'attribut de validation intégrée.



Problème - 4

Exemple, vous avez ce qui suit HTML

<input type="text" name="textBox1" value="harsha" customAttr1 = "MyValue" />

Question : Comment pouvons-nous accéder à la valeur de customAttr1 à partir de ce qui précède, par exemple de l'intérieur le contrôleur

Réponse: Lorsqu'un formulaire est publié, seuls le nom et la valeur des éléments sont renvoyés au serveur.

Alternatives: Utilisez un peu de jQuery pour obtenir les valeurs d'attributs personnalisés, et postez-les avec les valeurs du formulaire dans la méthode d'action

Une autre option consiste plutôt à mettre ce que vous avez dans vos attributs personnalisés dans des contrôles cachés




C'est la raison, je préfère toujours utiliser View-Models

46
Imad Alazani

Le seul avantage auquel je peux penser est que vous souhaitez utiliser le contrôleur généré automatiquement fourni lorsque vous ne spécifiez pas un modèle EF à utiliser pour taper fortement. Dans ce cas, vos actions Créer et Modifier utiliseront l'objet FormCollection car il s'agit d'un artefact préexistant fiable du framework avec lequel travailler à cette fin. Peut-être que le développeur précédent a choisi cette option lors de la création de ses contrôleurs, et qu'il est resté avec car Visual Studio doit savoir ce qu'il fait :)

Mais, en réalité, je ne recommanderais jamais cette longueur d'avance de quelques secondes. Il est toujours préférable de construire des modèles de vue, je recommanderais de regarder l'effort pour aller dans cette direction, ne serait-ce qu'à des fins de maintenance. Avec la liaison de modèle et les vues fortement typées et les aides html, vous êtes beaucoup plus susceptible de réduire le nombre d'erreurs d'exécution en modifiant une chaîne magique et en ne le réalisant pas jusqu'à ce que votre page explose.

7
Mister Epic

Ok, je vois le consensus général ici, c'est que ça ne plaît pas. Pour offrir une autre perspective, j'ai toujours aimé utiliser la collection de formulaires passée dans le contrôleur sur les actions POST. Elle propose l'utilisation de la méthode TryUpdateModel du contrôleur qui mappera la collection à votre modèle fortement tapé TryUpdateModel comporte également des surcharges qui vous permettent de mettre en liste blanche les propriétés du modèle que vous souhaitez autoriser à mettre à jour.

if (TryUpdateModel(viewModel, new string[] { "Name" }))
{
    //Do something
}

Il permet toujours toutes les liaisons de modèle que vous souhaitez, mais aide à empêcher toute mise à jour autre que la propriété "Nom" sur mon modèle de vue.

Vous pouvez en savoir plus sur la méthode TryUpdateModel ici:

http://msdn.Microsoft.com/en-us/library/system.web.mvc.controller.tryupdatemodel (v = vs.108) .aspx

6
RollemIra

Oui. Parfois, cela peut être utile. Voici un exemple:

Disons que nous avons dans notre base de données "date_and_time_field".

Dans Razor View, nous voulons utiliser deux champs de formulaire. Le premier "Date" (peut-être avec jQuery UI Datepicker). Le deuxième "Heure".

Dans l'action du contrôleur, nous composons le "champ_date_et_heure" au moyen de Request.Form["Date"] Et Request.Form["Hour"].

Il existe d'autres scénarios où cela peut être utile:

  • Un tableau croisé (avec checkBoxes en vue Razor)

  • La collection Request.Unvalidated().Form (peut-être que cela ne fait pas partie de votre question: je ne veux pas être hors sujet)

3
Fabio S

Le classeur de modèle par défaut fera presque tout ce dont vous avez besoin. J'ai eu recours à FormCollection une seule fois - seulement pour comprendre plus tard comment lier des tableaux d'éléments dans une collection sur le ViewModel.

Allez juste ViewModel. Mieux tout autour, pour toutes les raisons énumérées.

3
Chris Holmes

Avec form collection vous pourrez obtenir toutes les valeurs dans le formulaire. Il peut y avoir des situations où vous devrez peut-être passer des valeurs supplémentaires à partir du formulaire qui peuvent ne pas faire partie de votre view model.

Prenons simplement un exemple de passage de 10 valeurs masquées du formulaire. La collection de formulaires a du sens.

La seule difficulté que vous pouvez rencontrer est le lancer de type. Tous les éléments de collection de formulaires que vous obtenez seront des chaînes; vous devrez peut-être type cast en fonction de vos besoins.

La validation de l'état du modèle est également un autre domaine où vous pouvez faire face à un défi.

3
sudil ravindran pk

Il existe toujours des solutions de contournement pour vous éloigner d'un FormCollection lol .. vous pouvez avoir des champs cachés liés à vos variables de modèle de vue dans le formulaire au contenu de votre cœur.

Les collections de formulaires émergent principalement de la paresse de créer un modèle de vue mais finissent toujours par prendre du temps à essayer de comprendre comment en extraire les valeurs dans votre contrôleur: P

Je pense qu'il a été simplement créé au tout début de MVC comme une alternative à l'utilisation de vues fortement typées lorsque les formulaires sont très simples - à l'époque où tout le monde utilisait ViewBag :) ... et une fois qu'ils l'ont fait, ils ne pouvaient pas il suffit de le retirer aussi simple que ça.

Peut-être pouvez-vous l'utiliser si vous êtes absolument sûr que votre vue n'aura jamais plus d'une entrée de formulaire? Probablement encore une mauvaise idée.

Je ne trouve aucun article récent parlant des avantages des collections de formulaires .. alors que les vues fortement typées sont partout.

3
krilovich

Répondre à la question du titre: oui.

Dans certaines situations, FormCollection doit être utilisé. Par exemple, supposons un ViewModel qui a une propriété qui implémente la relation 1 à N (dans le cas concret, un TimesheetViewModel avec ICollection<TimesheetEntryViewModel>), et le contrôleur doit effectuer une validation entre les entrées de temps pour ne pas obtenir une collision de temps entre l'heure de fin d'une entrée et l'heure de début de l'entrée suivante. Pour marquer une entrée associée avec une erreur de validation, comment récupérer l'index de ligne?

Eh bien, avec la liaison de modèle par défaut, la valeur d'index est perdue dans la logique du contrôleur. Heureusement, FormController stocke l'index que vous avez utilisé dans View et une validation plus spécifique peut être effectuée.

2

Vous pouvez toujours ajouter les propriétés de collection de formulaires à vos signatures de méthode. Ils seront automatiquement remplis par les valeurs du formulaire avec les clés correspondantes.

2
Captain Kenpachi

Eh bien avec Collection de formulaires vous trouverez un moyen rapide d'obtenir les valeurs d'un formulaire. Sinon, vous devez créer une classe qui imite les champs de formulaire et les gens sont parfois paresseux pour créer des classes personnalisées pour les formulaires moins importants/rarement utilisés.

Non, il n'y a aucun avantage supplémentaire (en fait limité) de la collecte de formulaires sur une classe personnalisée en tant que paramètres d'action et cela doit être évité autant que possible.

2
kazimanzurrashid