IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

ASP.NET Discussion :

Héritage model binding MVC asp core.net 2.2


Sujet :

ASP.NET

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre émérite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2010
    Messages
    479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2010
    Messages : 479
    Par défaut Héritage model binding MVC asp core.net 2.2
    Bonjour,
    je sèche sur ce problème depuis deux jours.. pourriez-vous m'aider svp.
    Le but est de faire de l'héritage sur un formulaire de création. On a une classe de base abstraite Personne et deux classes dérivées Etudiant qui expose une prop moyenne professeur qui expose une prop Salaire. Pas très original mais c'est un poc qui ne représente pas du tout l'app finale.

    Le modèle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
     
    namespace PocHeritage.Models
    {
        [JsonConverter(typeof(PersonneJsonConverter))]
        public abstract class Personne
        {
            public long Id { get; set; }
            public string Nom { get; set; }
            public string Prenom { get; set; }
        }
     
        public class Etudiant : Personne
        {
            public double Moyenne { get; set; }
        }
     
        public class Professeur : Personne
        {
            public double Salaire { get; set; }
        }
     
        public abstract class JsonCreationConverter<T> : JsonConverter
        {
            public override bool CanWrite { get; } = false;
     
            public override bool CanRead { get; } = true;
     
            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
            }
     
            protected abstract T Create(Type objectType, JObject jObject);
     
            public override bool CanConvert(Type objectType)
            {
                return typeof(T) == objectType;
            }
     
            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                var jObject = JObject.Load(reader);
     
                var target = Create(objectType, jObject);
     
                serializer.Populate(jObject.CreateReader(), target);
     
                return target;
            }
        }
     
        public class PersonneJsonConverter : JsonCreationConverter<Personne>
        {
            protected override Personne Create(Type objectType, JObject jObject)
            {
                if(jObject["Salaire"] != null)
                {
                    return new Professeur();
                }
                else
                {
                    return new Etudiant();
                }
            }
        }
    }
    La vue Create :
    Code CSHTML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    @model PocHeritage.Models.Personne
     
    @{
        ViewData["Title"] = "Create";
    }
     
    <h1>Create</h1>
     
    <h4>Personne</h4>
    <hr />
    <div class="row">
        <div class="col-md-4">
            <form method="post" asp-action="Create">
                <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                <div class="form-group">
                    <label asp-for="Nom" class="control-label"></label>
                    <input asp-for="Nom" class="form-control" />
                    <span asp-validation-for="Nom" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="Prenom" class="control-label"></label>
                    <input asp-for="Prenom" class="form-control" />
                    <span asp-validation-for="Prenom" class="text-danger"></span>
                </div>
                <select id="selTypePers" onchange="TypePersonneChange()">
                    <option>-</option>
                    <option>Etudiant</option>
                    <option>Professeur</option>
                </select>
                <hr />
                <div id="divEtudiant" style="display:none">
                    <partial name="PartialViewCreateEtudiant" />
                </div>
                <div  id="divProfesseur" style="display:none">
                    <partial name="PartialViewCreateProfesseur" />
                </div>
                <div class="form-group">
                    <input type="submit" value="Create" class="btn btn-primary" />
                </div>
            </form>
        </div>
    </div>
     
    @section Scripts {
        @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
     
        <script>
            function TypePersonneChange() {
                var selectField = document.getElementById("selTypePers");
                var selectedType = selectField.options[selectField.selectedIndex].value;
                var length = $('#selTypePers option').length;
                for (var i = 0; i < length; i++) {
                    var type = selectField.options[i].value;
                    var div = document.getElementById("div" + type);
                    if (div != null) {
                        if (type == selectedType) {
                            div.style.display = "block";
                        }
                        else {
                            div.style.display = "none";
                        }
                    }
                }
            }
     
        </script>
    }

    La vue partielle prof :
    Code CSHTML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @model PocHeritage.Models.Professeur
     
    <div class="row">
        <div class="col-md-4">
                <div class="form-group">
                    <label asp-for="Salaire" class="control-label"></label>
                    <input asp-for="Salaire" class="form-control" />
                    <span asp-validation-for="Salaire" class="text-danger"></span>
                </div>
        </div>
    </div>
     
    @section Scripts {
        @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    }

    La vue partielle Etudiant :
    Code CSHTML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @model PocHeritage.Models.Etudiant
     
    <div class="row">
        <div class="col-md-4">
            <div class="form-group">
                <label asp-for="Moyenne" class="control-label"></label>
                <input asp-for="Moyenne" class="form-control" />
                <span asp-validation-for="Moyenne" class="text-danger"></span>
            </div>
        </div>
    </div>
     
    @section Scripts {
        @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    }

    Le contrôleur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using PocHeritage.Models;
     
    namespace PocHeritage.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class PersonneController : Controller
        {
     
            public ActionResult Create()
            {
                return View();
            }
     
            [HttpPost]
            public IActionResult Create([FromForm] Personne p)
            {
                return View(p);
            }
        }
    }
    En PJ le zip 7z de la solution.

    Sachant que je me suis inspiré de cette page https://www.tutorialdocs.com/article...a-binding.html

    Les vues ne sont pas blindées il y a plein de défauts ok; simplement le but est de récupérer une instance de prof ou etudiant grâce à l'attribut JsonConverter qui préférence le type de classe PersonneJsonConverter.
    Je pense avoir réalisé l'exemple assez fidèlement pourtant je reçois une exception :
    InvalidOperationException: Could not create an instance of type 'PocHeritage.Models.Personne'. Model bound complex types must not be abstract or value types and must have a parameterless constructor. Alternatively, give the 'p' parameter a non-null default value.
    Signe que le mécanisme de binding model essaye d'instancier la classe Personne au lieu d'utiliser le mécanisme jsonConverter pour instancier un étudiant ou un prof.

    Par avance merci pour votre aide.

    Cordialement,
    Fichiers attachés Fichiers attachés

  2. #2
    Membre très actif
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2007
    Messages
    871
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Février 2007
    Messages : 871
    Par défaut Pense plus simplement
    So oublie le json converter, ça va plus te créer d'ennuis que te faciliter la vie.
    Tu as une vue avec 2 sous vues potentielles, le plus simple serait de bouger ton submit dans les sous vues:

    Code CSHTML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <div id="divEtudiant" style="display:none">
        <partial name="PartialViewCreateEtudiant" />
    </div>
    <div  id="divProfesseur" style="display:none">
        <partial name="PartialViewCreateProfesseur" />
    </div>
    <div class="form-group">
        <input type="submit" value="Create" class="btn btn-primary" />
    </div>

    Deviens donc:
    Code CSHTML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <div id="divEtudiant" style="display:none">
        <partial name="PartialViewCreateEtudiant" />
    <div class="form-group">
       <input type="submit" value="Create" form-action="CreateEtudiant" class="btn btn-primary" />
    </div>
    </div>
     
    <div  id="divProfesseur" style="display:none">
       <partial name="PartialViewCreateProfesseur" />
    </div>
    <div class="form-group">
       <input type="submit" value="Create"  form-action="CreateProfesseur" class="btn btn-primary" />
    </div>

    Du coup au lieu d'avoir une seule action de post tu peux en avoir 2 avec les modeles specifiques:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [HttpPost]
    public IActionResult CreateEtudiant([FromForm] Etudiant p)
    {
       return View(p);
    }
     
    [HttpPost]
    public IActionResult CreateProfesseur([FromForm] Professeur p)
    {
       return View(p);
    }
    Enfin cote modele ca donne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    namespace PocHeritage.Models
    {
        public abstract class Personne
        {
            public long Id { get; set; }
            public string Nom { get; set; }
            public string Prenom { get; set; }
        }
     
        public class Etudiant : Personne
        {
            public double Moyenne { get; set; }
        }
     
        public class Professeur : Personne
        {
            public double Salaire { get; set; }
        }
    }

  3. #3
    Membre émérite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2010
    Messages
    479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2010
    Messages : 479
    Par défaut
    En effet c'est plus simple. J'implémente ça demain et je vous tiens au courant.
    Merci.

  4. #4
    Membre émérite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2010
    Messages
    479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2010
    Messages : 479
    Par défaut
    Hmmm en fait cette solution est valable pour le poc mais pas pour le projet final..

    On complexifie un tout petit peu pour que ça ressemble plus..

    On parle d'une classe voiture par exemple qui peut avoir un conducteur Personne qui peu-être soit étudiant soit professeur.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    public class Voiture
    {
    public long Id {get; set;}
    public string Immat {get; set;}
    public Personne Conducteur {get; set;}
    }
    Le contrôleur VoitureController a une méthode Create(Voiture voiture).

    Au moment du POST je reçois l'erreur susmentionnée car il n'arrive pas a instancier la propriété Conducteur.

  5. #5
    Membre très actif
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2007
    Messages
    871
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Février 2007
    Messages : 871
    Par défaut
    Personne possede un constructeur vide ?
    si non c'est ca le soucis.

    Quand bien meme il possede un constructeur vide, comment va tu faire la difference entre un etudiant et un professeur ?

    A ta place je creerai un seul gros objet personne avec ausis les proprietes de etudiant et de professeur, mais j'y inclurai aussi un enum qui donne le type de profil :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    public class Personne
    {
     prop Nom;
     prop Prenom;
     
     prop PersonneType;
     
     // on expose toujours le salaire.
     prop Salaire;
     
      // on expose toujours la moyenne.
      prop Moyenne;
     
    }
     
    public enum PersonneType
    {
       Etudiant,
       Professeur
    }
    Bon je sais ca ne ressemble plus du tout a de l'heritage, si tu tiens absoluement a avoir de l'heritage c'est possible mais le gain est minime.
    Ce qu'il faut bien comprendre avec mvc c'est que tes object presentes aux vues peuvent ne rien a voir a faire avec tes objets metiers.

  6. #6
    Membre émérite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2010
    Messages
    479
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2010
    Messages : 479
    Par défaut
    Finalement j'ai scindé en deux étapes. D'accord je créé la partie commune nom, prénom et le type et en suite dans le POST en fonction du type sélectionné je redirige vers le bon formulaire de création qui me retourne le "conducteur" typé.

    Pas simple l'asp
    C'est quand même moins flexible que le client lourd.. ou certainement que je manque de compétences pour faire ça. .net nous facilite bien la vie en général.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [C#]Héritage de classe en ASP.net
    Par stefsas dans le forum ASP.NET
    Réponses: 1
    Dernier message: 28/05/2010, 13h05
  2. héritage de form avec ASP.NET
    Par sophie1980 dans le forum ASP.NET
    Réponses: 3
    Dernier message: 21/04/2010, 11h22
  3. asp.net mvc + orm dataobject.net
    Par devstp dans le forum ASP.NET MVC
    Réponses: 12
    Dernier message: 25/03/2010, 11h26
  4. [MVC] Model Binding : cherche renseignements
    Par zax-tfh dans le forum ASP.NET
    Réponses: 1
    Dernier message: 23/12/2009, 02h11
  5. MVC & ASP.net : Quel framework utiliser ?
    Par LestoK dans le forum MVC
    Réponses: 4
    Dernier message: 03/06/2008, 12h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo