• Aucun résultat trouvé

5.3 Utiliser un modèle fortement typé pour passer des informations à la vue

La méthode précédente a l'inconvénient de ne pas permettre la détection d'erreurs avant l'exécution. Ainsi si la vue [Action01.cshtml] utilise le code

<h4>@ViewBag.Info</h4>

on aura une erreur car la propriété [Info] n'existe pas. Celle créée par l'action [Action01] s'appelle [info]. On peut alors utiliser un modèle fortement typé pour éviter ce désagrément.

Dans un des exemples étudiés précédemment, l'action était la suivante :

1. // Action10

2. public ContentResult Action10(ActionModel03 modèle) 3. {

4. string erreurs = getErrorMessagesFor(ModelState);

5. string texte = string.Format("email={0}, jour={1}, info1={2}, info2={3}, info3={4}, erreurs={5}",

7. return Content(texte, "text/plain", Encoding.UTF8); 8. }

L'action [Action10] transmettait à son client six informations (Email, Jour, Info1, Info2, Info3, erreurs) sous la forme d'une chaîne de caractères. Nous allons transmettre ces informations dans un modèle de vue [ViewModel01]. Comme ce modèle reprend des informations de [ActionModel03] nous allons le faire dériver cette classe.

Nous commençons par recopier [ActionModel03] du projet [Exemple-02] dans le projet [Exemple-03] actuel :

et nous changeons son espace de noms pour reprendre celui du projet [Exemple-03] :

1. using System.ComponentModel.DataAnnotations;

2. namespace Exemple_03.Models

3. {

4. public class ActionModel03

5. {

6. [Required(ErrorMessage = "Le paramètre email est requis")]

7. [EmailAddress(ErrorMessage = "Le paramètre email n'a pas un format valide")] 8. public string Email { get; set; }

9.

10. [Required(ErrorMessage = "Le paramètre jour est requis")]

11. [RegularExpression(@"^\d{1,2}$", ErrorMessage = "Le paramètre jour doit avoir 1 ou 2 chiffres")]

12. public string Jour { get; set; } 13.

14. [Required(ErrorMessage = "Le paramètre info1 est requis")]

15. [MaxLength(4, ErrorMessage = "Le paramètre info1 ne peut avoir plus de 4 caractères")] 16. public string Info1 { get; set; }

17.

18. [Required(ErrorMessage = "Le paramètre info2 est requis")]

19. [MinLength(2, ErrorMessage = "Le paramètre info2 ne peut avoir moins de 2 caractères")] 20. public string Info2 { get; set; }

21.

22. [Required(ErrorMessage = "Le paramètre info3 est requis")]

23. [MinLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")] 24. [MaxLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")] 25. public string Info3 { get; set; }

26. } 27. }

• ligne 2 : le nouvel espace de noms ; Puis nous créons la classe [ViewModel01] :

Le code de [ViewModel01] est le suivant :

1. namespace Exemple_03.Models

2. {

3. public class ViewModel01 : ActionModel03

4. {

5. public string Erreurs { get; set; } 6. }

7. }

• ligne 3 : la classe hérite de [ActionModel03] et donc des propriétés [Email, Jour, Info1, Info2, Info3] ; • ligne 5 : on lui rajoute la propriété [Erreurs].

Nous écrivons maintenant l'action [Action02] qui :

• accepte en entrée le modèle d'action [ActionModel03] ; • et délivre en sortie le modèle de vue [ViewModel01]. Son code est le suivant :

1. // Action02

2. public ViewResult Action02(ActionModel03 modèle) 3. {

4. string erreurs = getErrorMessagesFor(ModelState);

5. return View(new ViewModel01(){Email=modèle.Email, Jour=modèle.Jour, Info1=modèle.Info1, Info2=modèle.Info2, Info3=modèle.Info3, Erreurs=erreurs}); 6. }

• ligne 1 : [Action02] reçoit le modèle d'action [ActionModel03]. Elle rend un résultat de type [ViewResult] ;

• ligne 4 : les erreurs liées au modèle d'action [ActionModel03] sont agrégées dans la chaîne de caractères [erreurs]. La méthode [getErrorMessagesFor] a été décrite page 73 et a été incluse dans le contrôleur [First] du nouveau projet ; • ligne 5 : la méthode [View] est appelée avec un paramètre. Celui est le modèle de la vue. Cette dernière n'est pas précisée.

Ce sera donc la vue par défaut [/Views/First/Action02] qui sera utilisée. Le modèle de vue [ViewModel01] est instancié et initialisé avec les cinq informations du modèle d'action [ActionModel03] et l'information [erreurs] construite ligne 4. Nous construisons maintenant la vue [/First/Action02.cshtml] :

Son code est le suivant :

1. @model Exemple_03.Models.ViewModel01

2. @{ 3. Layout = null; 4. } 5. 6. <!DOCTYPE html> 7. 8. <html> 9. <head>

10. <meta name="viewport" content="width=device-width" /> 11. <title>Action02</title>

12.</head> 13.<body>

14. <h3>Informations du modèle de vue</h3> 15. <ul>

16. <li>Email : @Model.Email</li> 17. <li>Jour : @Model.Jour</li> 18. <li>Info1 : @Model.Info1</li>

19. <li>Info2 : @Model.Info2</li> 20. <li>Info3 : @Model.Info3</li> 21. <li>Erreurs : @Model.Erreurs</li> 22. </ul> 23.</body> 24.</html>

• la nouveauté réside en ligne 1. La notation [@model] fixe le type du modèle de la vue. Ce modèle est ensuite référencé par la notation [@Model] (lignes 16-21) ;

• lignes 16-21 : les informations du modèle sont affichées dans une liste. Voyons quelques exemples d'exécution de l'action [Action02].

D'abord sans paramètres :

puis avec des paramètres incorrects :

Dans cet exemple, le modèle de la vue [ViewModel01] reprend les informations du modèle d'action [ActionModel03]. C'est souvent le cas. On peut alors utiliser un unique modèle qui servira à la fois de modèle d'action et de vue. Nous créons un nouveau modèle [ActionModel04] :

qui sera le suivant :

1. using System.ComponentModel.DataAnnotations;

2. using System.Web.Mvc;

3. namespace Exemple_03.Models

4. {

5. [Bind(Exclude="Erreurs")] 6. public class ActionModel04

7. {

8. // --- Action ---

9. [Required(ErrorMessage = "Le paramètre email est requis")]

10. [EmailAddress(ErrorMessage = "Le paramètre email n'a pas un format valide")] 11. public string Email { get; set; }

12.

13. [Required(ErrorMessage = "Le paramètre jour est requis")]

14. [RegularExpression(@"^\d{1,2}$", ErrorMessage = "Le paramètre jour doit avoir 1 ou 2 chiffres")]

15. public string Jour { get; set; } 16.

17. [Required(ErrorMessage = "Le paramètre info1 est requis")]

18. [MaxLength(4, ErrorMessage = "Le paramètre info1 ne peut avoir plus de 4 caractères")] 19. public string Info1 { get; set; }

20.

21. [Required(ErrorMessage = "Le paramètre info2 est requis")]

22. [MinLength(2, ErrorMessage = "Le paramètre info2 ne peut avoir moins de 2 caractères")] 23. public string Info2 { get; set; }

24.

25. [Required(ErrorMessage = "Le paramètre info3 est requis")]

26. [MinLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")] 27. [MaxLength(4, ErrorMessage = "Le paramètre info3 doit avoir 4 caractères exactement")] 28. public string Info3 { get; set; }

29.

30. // --- vue ---

31. public string Erreurs { get; set; } 32. }

33. }

• lignes 8-28 : le modèle de l'action avec ses contraintes d'intégrité. Ces champs feront également partie de la vue ; • ligne 31 : une propriété propre au modèle de la vue. Elle a été exclue du modèle de l'action par l'annotation de la ligne 5. Nous créons la nouvelle action [Action03] suivante :

1. // Action03

2. public ViewResult Action03(ActionModel04 modèle) 3. {

4. modèle.Erreurs = getErrorMessagesFor(ModelState); 5. return View(modèle);

6. }

• ligne 2 : [Action03] reçoit le modèle d'action de type [ActionModel04] ; • ligne 5 : et rend comme modèle de vue, ce même modèle ;

• ligne 4 : complété par l'information [Erreurs] ; Il ne nous reste qu'à créer la vue [/First/Action03.cshtml] :

• en [1] : clic droit dans le code de [Action03] puis [Ajouter une vue] ; • en [2] : le nom de la vue proposée par défaut ;

• en [3] : indiquer qu'on crée une vue fortement typée ;

• en [4] : prendre dans la liste déroulante la bonne classe, ici la classe [ActionModel04] ; • en [5] : la vue créée.

Nous donnons à la vue [Action03] le même code qu'à la vue [Action02]. Seul le modèle de vue (ligne 1) et le titre de page (ligne 11) changent :

1. @model Exemple_03.Models.ActionModel04

2. @{ 3. Layout = null; 4. } 5. 6. <!DOCTYPE html> 7. 8. <html> 9. <head>

10. <meta name="viewport" content="width=device-width" /> 11. <title>Action03</title>

12.</head> 13.<body>

14. <h3>Informations du modèle de vue</h3> 15. <ul> 16. <li>Email : @Model.Email</li> 17. <li>Jour : @Model.Jour</li> 18. <li>Info1 : @Model.Info1</li> 19. <li>Info2 : @Model.Info2</li> 1 2 3 4 5

20. <li>Info3 : @Model.Info3</li> 21. <li>Erreurs : @Model.Erreurs</li> 22. </ul>

23.</body> 24.</html>

Maintenant demandons l'action [Action03] sans paramètres :

Les résultats sont les mêmes qu'auparavant. Il est fréquent d'utiliser le même modèle pour l'action et la vue car le modèle de la vue reprend souvent des informations du modèle de l'action. On utilise alors un modèle plus large, utilisable à la fois par l'action et la vue que celle-ci génère. On prendra soin d'exclure de la liaison de données, les informations qui n'appartiennent pas au modèle de l'action. Sinon, un utilisateur bien renseigné pourrait initialiser des parties du modèle de la vue à notre insu.