Éditeur pour modèle d’inheritance MVC

Mon appel Post ne renvoie pas le type de modèle correct. Il utilise toujours l’object baseObject au lieu de l’object dérivé correct que j’ai transmis de la commande Get.

RestaurantViewModel.cs

public class RestaurantViewModel{ public Food BaseFoodObject{get;set;} } 

Nourriture.cs

 public class Food{ public ssortingng Price{get;set;) } 

Pain.cs – Hériter de la nourriture

 public class Bread:Food{ public int Unit{get;set;} } 

Lait.cs – Hériter de la nourriture

 public class Milk:Food{ public ssortingng Brand{get;set} } 

Éditeur pour modèle de pain. Afficher l’unité et permettre à l’utilisateur de modifier

Index.html

 @Model RestaurantViewModel @using(Html.BeginForm("SaveFood", "Food")) { @Html.EditorFor(m=>m.BaseFoodObject)  } 

Pain.cshtml

 @Model Bread 
@Html.TextboxFor(bread=>bread.Unit)

FoodController.cs

 public ActionResult Index(){ Bread bread = new Bread(){ Price = "$10", Unit = 1 } RestaurantViewModel viewModel = new RestaurantViewModel(){ BaseFoodObject = bread } return View(viewModel); } public ActionResult Post(RestaurantViewModel viewModelPost) { // When I inspect the viewModelPost, there is no atsortingbute for unit } 

Résultat final: 1. L’affichage semble correct. EditorFor est suffisamment intelligent pour choisir le bon modèle d’éditeur et afficher correctement la valeur 2. L’enregistrement ne fonctionne pas . L’atsortingbut Unité de l’ object Pain n’est pas transmis avec RestaurantViewModel . La raison en est que RestaurantViewModel a utilisé l’object Food au lieu de Bread

J’espère qu’il est possible de modifier EditorFor et de lui dire d’utiliser le modèle dans la vue ou le type d’object que j’ai transmis lorsque je l’affiche.

Merci

Mise à jour 1: J’ai résolu ce problème en utilisant le classeur personnalisé et en utilisant une usine pour décider quel object je veux vraiment. Cela aide à construire le bon modèle que je veux

MVC est apasortingde. Quelques références .

Dans votre question, il y a quelques déclarations qui entrent en conflit avec ceci, et comment fonctionne la liaison MVC, par exemple:

Mon appel Post ne renvoie pas le type de modèle correct.

Peut-être juste de la terminologie, mais votre appel Post ne «retourne pas un type de modèle» – il entre dans le modèle défini dans l’action Post, dans le cas présent, RestaurantViewModel .

au lieu de l’object dérivé correct que j’ai transmis de la commande Get

comme il est apasortingde, il ne sait rien du modèle que vous avez transmis depuis le get … absolument rien.

Le code HTML final rendu via le modèle getaction + view.cshtml + n’est pas lié à la postaction. Vous pouvez tout aussi facilement prendre le rendu HTML, le sauvegarder, redémarrer votre PC, recharger le rendu HTML et il fonctionnera exactement de la même manière.

un moyen de modifier le EditorFor et lui dire d’utiliser le modèle dans la vue ou le type d’object que j’ai transmis lorsque je l’affiche

Lorsque vous utilisez EditorFor il définit un atsortingbut ID et name fonction du modèle EditorFor il était lié. Il le fait déjà, mais vous ne liez peut-être pas le modèle EditorFor vous EditorFor vous EditorFor pour obtenir le bon id .


Donc, à la question, si, dans le code C # ‘normal’, vous instanciiez une nouvelle instance de RestaurantViewModel , qu’attendriez-vous du type BaseFoodObject?

C’est ce que ModelBinder est en train de créer: créer un nouveau RestaurantViewModel .

Comme la signature de votre méthode post action n’inclut aucun élément relatif au Bread , toutes les propriétés du pain sont ignorées.

Quelques options:


Vérifiez les propriétés des aliments après la liaison et lisez-les manuellement (probablement le plus rapide + le plus facile mais pas très “mvc-ish”)

 public ActionResult Post(RestaurantViewModel viewModelPost) { if (!ssortingng.IsNullOrEmpty(Request.Form["Unit"])) // it's a bread form 

pour rendre cela plus facile, vous pouvez fournir un champ caché avec le type

  if (Request.Form["Type"] == typeof(Bread).Name) { var bread = new Bread { Unit = Request.Form["Unit"] } 

Ajoutez du pain à l’action pour qu’il soit lié

 public ActionResult Post(RestaurantViewModel viewModelPost, Bread bread) 

mais alors, évidemment, cela ne fonctionnera pas pour le lait.

Donc, pourrait étendre cela en utilisant un ActionNameSelector pour sélectionner l’action correcte

 public ActionResult PostBread(RestaurantViewModel viewModelPost, Bread bread) public ActionResult PostMilk(RestaurantViewModel viewModelPost, Milk milk) [AtsortingbuteUsage(AtsortingbuteTargets.Method, AllowMultiple = false)] public sealed class FoodSelectorAtsortingbute : ActionNameSelectorAtsortingbute { public override bool IsValidName(ControllerContext controllerContext, ssortingng actionName, MethodInfo methodInfo) { ... check if provided parameters contains bread/milk 

( lien connexe mais pas une solution à ce cas particulier)


Une autre option pourrait consister à remplacer le type de restaurant par un type générique, mais cela nécessiterait quelques modifications supplémentaires (et idéalement l’utilisation d’interfaces), ainsi que davantage de détails (fournis ici à titre d’idée plutôt que de solution).

Les bases seraient:

 public class RestaurantViewModel where T: Food { } public ActionResult Post(RestaurantViewModel viewModelPost) public ActionResult Post(RestaurantViewModel viewModelPost) 

mais je n’ai pas encore confirmé si le ModelBinder par défaut fonctionnerait dans ce cas.

Le problème vient avec le post. Une fois que vous publiez, tout ce que vous avez est un dataset publiées et un paramètre de type, RestaurantViewModel . Le classeur de modèle définit tous les champs appropriés sur les Food parce que c’est tout ce qu’il sait. Tout le rest est jeté. Il n’y a rien qui peut être fait à ce sujet. Si vous devez afficher des champs en rapport avec Bread le type de votre propriété doit être Bread . C’est la seule façon dont cela fonctionnera.