Vous êtes sur la page 1sur 77

ASP.

NET MVC 5
Document de Rick Anderson

Mise en route
Visual Studio est un environnement de développement intégré ou IDE. Dans Visual Studio, il y
a une barre d'outils dans la partie supérieure montrant les différentes options disponibles à vous. Il y
a aussi un menu qui fournit un autre moyen d'effectuer des tâches dans l'environnement IDE. (Par
exemple, au lieu de sélectionner le Nouveau projet de la page de démarrage, vous pouvez utiliser le
menu et sélectionnez Fichier > Nouveau > projet.)
Créer votre première Application
Cliquez sur Nouveau projet, puis sélectionnez Visual Basic sur la gauche, puis le Web et puis
sélectionnez Application Web ASP.NET. Nommez votre projet « MvcMovie » et puis cliquez sur OK.

Dans la boite de dialogue Nouveau projet ASP.NET, cliquez sur MVC et puis cliquez sur OK.
Visual Studio utilise un modèle par défaut pour le projet ASP.NET MVC, que vous venez de
créer. Vous avez une application qui travaille dès maintenant sans rien faire ! Il s'agit d'un simple projet
de « Hello World! ».

Cliquez sur F5 pour démarrer le débogage. F5 oblige Visual Studio à lancer IIS Express et
exécutez votre application web Visual Studio puis lance un navigateur et ouvre la page d'accueil de
l'application. Remarquez que la barre d'adresse du navigateur affiche localhost:port# . Lorsque Visual
Studio exécute un projet web, un port aléatoire est utilisé pour le serveur web. Dans l'image ci-dessous,
le numéro de port est 55532. Lorsque vous exécutez l'application, vous verrez un autre numéro de
port.
Dès la sortie de la boite de ce modèle par défaut vous donne des pages Accueil, Contact et
environ. L'image ci-dessus n'affiche pas les liens Accueil, propos et Contact. Selon la taille de la fenêtre
de votre navigateur, vous devrez peut-être cliquer sur l'icône de navigation pour voir ces liens.

L'application assure également pour vous inscrire et vous connecter. L'étape suivante consiste
à modifier le fonctionne de cette application et en savoir un peu plus sur ASP.NET MVC. Fermez
l'application ASP.NET MVC et nous allons changer du code.
Ajout d'un contrôleur
MVC est synonyme de modèle-vue-contrôleur. MVC est un pattern pour développer des
applications qui sont bien architecturé, testables et facile à entretenir. Contiennent des applications
basées sur le MVC :
• Modélisation : Classes qui représentent les données de l'application et qui utilisent une logique
de validation pour faire respecter les règles de métier pour que les données.
• Views : fichiers de modèle que votre application utilise pour générer dynamiquement les
réponses HTML.
• Controllers : Classes qui gèrent les demandes entrantes de navigateur, récupérer des données
de modèle et ensuite spécifier des modèles de vue qui retournent une réponse au navigateur.
Nous couvrant tous ces concepts et vous montrer comment s'en servir pour construire une
application. Nous allons commencer par créer une classe de contrôleur.

Dans de L'Explorateur de solutions, faites un clic droit le dossier controllers, puis cliquez sur
Ajouter, puis Contrôleur.
Dans la boite de dialogue Ajouter un modèle automatique, cliquez sur Contrôleur MVC 5 –
Vide et puis cliquez sur Ajouter.

Nommez votre nouveau contrôleur « HelloWorldController », puis cliquez sur Ajouter.

Notez que dans L'Explorateur qu'un nouveau fichier a été créé nommé
HelloWorldController.vb et un nouveau dossier Views\HelloWorld. Le contrôleur est ouvert dans l'IDE.
Remplacez le contenu du fichier avec le code suivant.
Imports System.Web.Mvc

Public Class HelloWorldController


Inherits Controller

' GET: /HelloWorld


Function Index() As String
Return "This is my <b>default</b> action..."
End Function

'GET: /HelloWorld/Welcome/
Function Welcome() As String
Return "This is the Welcome action method..."
End Function
End Class
Les méthodes du contrôleur retourneront des chaines HTML à titre d'exemple. Le contrôleur
est appelé HelloWorldController et la première méthode est nommée Index. Nous allons appeler à
partir d'un navigateur. Exécutez l'application (en appuyant sur F5 ou Ctrl + F5). Dans le navigateur,
ajoutez « HelloWorld » le chemin d'accès dans la barre d'adresse. (Par exemple, dans l'illustration ci-
dessous, c'est http://localhost:55532/HelloWorld.) La page dans le navigateur va ressembler à la
capture d'écran suivante. Dans la méthode ci-dessus, le code renvoyé une chaine directement.

ASP.NET MVC appelle classes contrôleur différent (et les méthodes d'action différents en leur
sein) selon l'URL entrante. La logique de routage d’URL par défaut utilisée par ASP.NET MVC utilise un
format comme celui-ci pour déterminer quel code pour appeler :

/[Controller]/[ActionName]/[Parameters]

Vous définissez le format de routage dans le fichier App_Start/RouteConfig.vb.


Public Module RouteConfig
Public Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")

routes.MapRoute(
name := "Default",
url := "{controller}/{action}/{id}",
defaults := New With {.controller = "Home", .action = "Index", .id =
UrlParameter.Optional}
)
End Sub
End Module
Le slash (/) est un séparateur de segment. Lorsque vous exécutez l'application et ne fournissez
pas des segments d'URL, il utilise par défaut le contrôleur « Home » et la méthode d'action « Index »
spécifié dans la section valeurs par défaut du code ci-dessus.
La première partie de l'URL détermine la classe du contrôleur à exécuter. Si /HelloWorld est
mappé à la classe HelloWorldController. La deuxième partie de l'URL détermine la méthode d'action
de la classe à exécuter. Ainsi, /HelloWorld/Index évoquera l’exécution de la méthode Index de la classe
HelloWorldController. Notez que /HelloWorld nous renvoie à la même page et le méthode Index a été
utilisée par défaut. C'est parce qu'une méthode nommée Index est la méthode par défaut qui sera
appelée sur un contrôleur si on n'est pas spécifiée une explicitement. La troisième partie du segment
URL (Parameters) est pour acheminer les données.
Accédez à http://localhost:xxxx/HelloWorld/Welcome. Le méthode Welcome s'exécute et
retourne la chaine " This is the Welcome action method... ". Le mappage de MVC par défaut est
/[Controller]/[ActionName]/[Parameters]. Pour cette URL, le contrôleur est HelloWorld et Welcome
est la méthode d'action. Vous n'avez pas utilisé la partie [Parameters] de l'URL.

Nous allons modifier l'exemple un peu afin que vous pouvez passer des informations de
paramètre de l'URL au contrôleur (par exemple, /HelloWorld/Welcome?name=Scott&numtimes=4).
Changer votre méthode Welcome pour inclure deux paramètres comme indiqué ci-dessous. Notez que
le code utilise la fonctionnalité de paramètre optionnel vb pour indiquer que le paramètre numTimes
a une valeur par défaut égale à 1, si aucune valeur n'est passée pour ce paramètre.
Function Welcome(name As String, Optional numTimes As Integer = 1) As String
Return HttpUtility.HtmlEncode("Hello " & name & ", NumTimes is: " & numTimes)
End Function
Remarque sur la sécurité : Le code ci-dessus utilise HttpServerUtility.HtmlEncode pour
protéger l'application des entrées malveillantes (à savoir le JavaScript).
Lancez votre application et accédez à l'URL de l'exemple
(http://localhost:xxxx/HelloWorld/Welcome?name=Scott&numtimes=4). Vous pouvez essayer
différentes valeurs pour name et numtimes dans l'URL. Le système de liaison pour le modèle MVC
ASP.NET mappe automatiquement les paramètres nommés de la chaine de requête dans la barre
d'adresse aux paramètres dans votre méthode.
Dans l'exemple ci-dessus, le segment d'URL (Parameters) n'est pas utilisé, les paramètres name
et numTimes sont transmis sous forme de chaines de requête. Le ? (point d'interrogation) dans l'URL
ci-dessus est un séparateur, et suivent les chaines de requête. Le caractère & sépare les chaines de
requête.
Remplacez la méthode Welcome avec le code suivant :
Function Welcome(name As String, Optional ID As Integer = 1) As String
Return HttpUtility.HtmlEncode("Hello " & name & ", ID: " & ID)
End Function
Exécutez l'application et entrez l'URL suivante :
http://localhost:xxx/HelloWorld/Welcome/3?name=Rick

Cette fois le troisième segment de l'URL correspondant du paramètre itinéraire ID. La méthode
d'action Welcome contient un paramètre (ID) correspondant à la spécification de l'URL dans la
méthode RegisterRoutes.
Public Module RouteConfig
Public Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")

routes.MapRoute(
name:="Default",
url:="{controller}/{action}/{id}",
defaults:=New With {.controller = "Home", .action = "Index", .id =
UrlParameter.Optional}
)
End Sub
End Module
Dans les applications ASP.NET MVC, il est plus courant pour passer des paramètres en tant que
données d'itinéraire (comme nous le faisions avec ID ci-dessus) que les transmettre sous forme de
chaines de requête. Vous pourriez également ajouter une route pour passer le name et numtimes dans
les paramètres sous forme de données d'itinéraire dans l'URL. Dans le fichier
App_Start\RouteConfig.vb, ajoutez la route de "Hello" :
Public Module RouteConfig
Public Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")

routes.MapRoute(
name:="Default",
url:="{controller}/{action}/{id}",
defaults:=New With {.controller = "Home", .action = "Index", .id =
UrlParameter.Optional}
)

routes.MapRoute(
name:="Hello",
url:="{controller}/{action}/{name}/{id}"
)
End Sub
End Module
Exécutez l'application et accédez à /localhost:XXX/HelloWorld/Welcome/Scott/3.

Pour de nombreuses applications MVC, l'itinéraire par défaut fonctionne très bien. Vous
apprendrez plus loin dans ce tutoriel comment passer des données à l'aide du modèle, et vous n'aurez
pas à modifier l'itinéraire par défaut pour cela.
Dans ces exemples, le contrôleur a fait la partie « VC » de MVC — autrement dit, le travail de
vue et le contrôleur. Le contrôleur est de retour HTML directement. Normalement, vous ne souhaitez
pas que le contrôleur retour HTML directement, car cela devient très lourd au code. Au lieu de cela,
nous utiliserons généralement un fichier de modèle de vue distincte afin de générer la réponse HTML.
Ajout d'une vue
Dans cette section, vous allez modifier la classe HelloWorldController pour afficher des fichiers
de modèle de vue permet d'encapsuler proprement le processus de génération de la réponse HTML à
un client.
Vous allez créer un fichier de modèle de vue en utilisant le moteur de vue Razor. Les modèles
de vue basée sur le rasoir portent une extension de fichier .vbhtml et fournir un moyen élégant pour
créer une sortie HTML à l'aide de vb. Rasoir minimise le nombre de caractères et de keystrokes requis
lors de l'écriture d'un modèle de vue et permet un codage rapide et fluide de flux de travail.
Actuellement, la méthode Index retourne une chaine avec un message qui est codé en dur
dans la classe de contrôleur. Changer la méthode Index pour renvoyer un objet View, comme illustré
dans le code suivant :
Function Index() As ActionResult
Return View()
End Function
La méthode Index ci-dessus utilise un modèle de vue générant une réponse HTML dans le
navigateur. Les méthodes des contrôleurs (également connues comme des méthodes d'action), telle
que la méthode Index ci-dessus, retournent généralement un ActionResult (ou une classe dérivée de
ActionResult) et des types non primitifs comme chaine.
Clic droit sur le dossier Views\HelloWorld et cliquez sur Ajouter, puis cliquez sur Page de vue
MVC 5 avec disposition (Razor).

Dans la boite de dialogue Spécifier le nom d'élément, entrez Index et puis cliquez sur OK.
Dans la boite de dialogue Sélectionner une Page de disposition, acceptez la valeur par défaut
_Layout.vbhtml, puis cliquez sur OK.

Dans la boite de dialogue ci-dessus, le dossier Views\Shared est sélectionné dans le volet
gauche. Si vous aviez un fichier de mise en page personnalisée dans un autre dossier, vous pouvez le
sélectionner. Le fichier MvcMovie\Views\HelloWorld\Index.vbhtml est créé.
Ajoutez la balise suivante de met en évidence.
@Code
Layout = "~/Views/Shared/_Layout.vbhtml"
ViewBag.Title = "Index"
End Code

<h2>Index</h2>

<p>Hello from our View Template!</p>


Faites un clic droit sur le fichier Index.vbhtml et sélectionnez afficher dans le navigateur.

Vous pouvez également cliquez droit sur le fichier Index.vbhtml et sélectionnez voir en Page
inspecteur. Sinon, exécutez l'application et naviguez vers le contrôleur de HelloWorld
(http://localhost:xxxx/HelloWorld). La méthode Index dans votre contrôleur n'a pas fait beaucoup de
travail ; simplement, il a appelé l'instruction return View(), qui précise que la méthode doit utiliser un
fichier de modèle de vue pour restituer une réponse au navigateur. Parce que vous n'a pas spécifier
explicitement le nom du fichier du modèle de vue à utiliser, ASP.NET MVC par défaut en utilisant le
fichier Index.vbhtml de la vue dans le dossier \Views\HelloWorld. L'image ci-dessous montre la chaîne
« Hello from our View Template! » codé en dur dans la vue.

Semble assez bonne. Toutefois, Notez que la barre de titre du navigateur indique « Index –
Mon application ASP.NET » et le gros lien en haut de la page dit « Nom de l'Application. ». Selon la
taille qui fait votre fenêtre de navigateur, vous devrez peut-être cliquez sur les trois barres en haut à
droite pour voir les liens Accueil, About, Contact, Inscrivez-vous et Connectez-vous.

Évolution des vues et Pages de disposition


Tout d'abord, vous souhaitez modifier le lien « Nom de l'Application » en haut de la page. Ce
texte est commun à toutes les pages. Elle est effectivement appliquée dans un seul endroit dans le
projet, même si elle apparait à toutes les pages de l'application. Allez dans le dossier /Views/Shared
dans L'Explorateur de solutions et ouvrez le fichier _Layout.vbhtml. Ce fichier s'appelle Layout Page
et c'est dans le dossier partagé qui utilisé par toutes les autres pages.

Le modèles de disposition permettent de préciser la disposition de conteneur HTML de votre


site en un seul endroit, puis l'appliquer sur plusieurs pages dans votre site. Recherchez la ligne de
@RenderBody(). RenderBody est un espace réservé où toutes les pages spécifiques à la vue que vous
créez afin d’apparaitre "encapsulés" dans la mise en page. Par exemple, si vous sélectionnez le lien du
sA propos de, le point de vue Views\Home\About.vbhtml est restitué à l'intérieur de la méthode
RenderBody.
Modifier le contenu de l'élément title. Changer l'ActionLink sur le modèle de mise en page de
"Nom de l'Application" à "MVC Movie" et le contrôleur de « Home » à « Movies ». Le fichier complet
de mise en page est illustré ci-dessous :
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - Mon application ASP.NET</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")

</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse"
data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink("MVC Movie", "Index", "Movies", New With {.area =
""}, New With {.class = "navbar-brand"})
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Accueil", "Index", "Home")</li>
<li>@Html.ActionLink("À propos de", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>&copy; @DateTime.Now.Year - My ASP.NET Application</p>
</footer>
</div>

@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required:=False)
</body>
</html>

Exécutez l'application et Notez qu'il dit maintenant « MVC Movie ». Cliquez sur le lien A propos
de et vous voyez comment cette page affiche aussi "MVC Movie". Nous avons été en mesure
d'apporter la modification une fois dans le modèle de disposition et toutes les pages du site ont
reflètent le nouveau titre.
Lorsque nous avons créé tout d'abord le fichier Views\HelloWorld\Index.vbhtml, il contient le
code suivant :
@Code
Layout = "~/Views/Shared/_Layout.vbhtml"
End Code
Le code de rasoir ci-dessus déclare explicitement la mise en page à utiliser. Examinez le fichier
Views\_ViewStart.vbhtml, il contient exactement la balise même de Razor. Le fichier
Views\_ViewStart.vbhtml définit la disposition commune utilisée par toutes les vues, donc vous pouvez
commenter dehors ou supprimer ce code dans le fichier Views\HelloWorld\Index.vbhtml.
@Code
'Layout = "~/Views/Shared/_Layout.vbhtml"
ViewBag.Title = "Index"
End Code

<h2>Index</h2>

<p>Hello from our View Template!</p>


Vous pouvez utiliser la propriété de Layout pour définir une vue de la mise en page différente
ou la mettre à null si vous voulez qu’aucun fichier de mise en page ne sera utilisé.
Maintenant, nous allons changer le titre de la vue Index. Ouvrez
MvcMovie\Views\HelloWorld\Index.vbhtml. Il y a deux endroits pour faire ce changement : tout
d'abord, le texte qui apparait dans le titre du navigateur, puis dans l'entête secondaire (l'élément
<h2>). Vous leur ferez légèrement différente afin de voir quel morceau de code change quelle partie
de l'application.
@Code
Layout = "~/Views/Shared/_Layout.vbhtml"
ViewBag.Title = "Movies List"
End Code

<h2>My Movies List</h2>

<p>Hello from our View Template!</p>

Pour indiquer l'élément title de HTML à afficher, le code ci-dessus définit une propriété Title
de l'objet ViewBag (qui est dans le modèle d'affichage Index.vbhtml). Notez que le modèle de
disposition (Views\Shared\_Layout.vbhtml) utilise cette valeur dans l'élément <title> dans le cadre de
la section <head> du code HTML que nous avons modifié précédemment.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - Mon application ASP.NET</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")

</head>
En utilisant l’objet ViewBag, vous pouvez passer facilement d’autres paramètres entre votre
modèle d'affichage et votre fichier de mise en page.
Exécutez l'application. Notez que le titre du navigateur, le titre principal et les titres
secondaires ont changé. (Si vous ne voyez pas de changements dans le navigateur, il pourrie que vous
regardez le contenu mis en cache. Appuyez sur Ctrl + F5 dans votre navigateur pour forcer la réponse
du serveur à se charger). Le titre du navigateur est créé avec le ViewBag.Title, nous avons mis dans le
modèle de vue Index.vbhtml concaténer à "-Mon application" ajouté dans le fichier de mise en page.
Notez également comment le contenu dans le modèle de vue Index.vbhtml a fusionné avec le
modèle d'affichage _Layout.vbhtml et une seule réponse HTML a été envoyée au navigateur. Modèles
de disposition rendent vraiment facile de faire les modifications qui s'appliquent dans l'ensemble de
toutes les pages dans votre application.

Notre peu de « données » (dans ce cas, le message « Hello from our View Template! ») est
codé en dur. Cependant, l'application MVC dispose d'un "V" (vue) et vous avez un "C" (contrôleur),
mais pas "M" (modèle) encore.

Passage de données du contrôleur à la vue


Avant que nous allons à intégrer un modèle, parlons de passer des informations du contrôleur
à une vue. Les classes contrôleur sont appelés en réponse à une demande d'URL entrante. Une classe
de contrôleur est l’endroit où vous écrivez le code qui gère la requête entrante, récupère les données
d'une base de données et en fin de compte décide quel type de réponse à envoyer au navigateur. Les
modèles de vue sont ensuite utilisables à partir d'un contrôleur pour générer une réponse HTML.
Les contrôleurs sont chargés de fournir toutes les données ou les objets qui sont requis pour
un modèle de vue afin de rendre une réponse au navigateur. Exemple : un modèle de vue ne doit
jamais exécuter la logique métier ou interagir avec une base de données directement. Au lieu de
cela, un modèle de vue devrait fonctionner uniquement avec les données qui sont fournies par le
contrôleur. Maintenir cette « séparation des préoccupations » permet de garder votre code propre,
testables et plus facile à gérer.
Actuellement, la méthode d'action Welcome dans la classe HelloWorldController prend un
name et un paramètre numTimes et ensuite renvoie les valeurs directement dans le navigateur. Plutôt
que d'avoir le contrôleur à rendre cette réponse sous forme de chaine, nous allons changer le
contrôleur pour utiliser un modèle de vue à la place. Le modèle de vue doit générer une réponse
dynamique, ce qui signifie que vous devrez passer des bits de données du contrôleur à la vue afin de
générer la réponse. Vous pouvez le faire en passant au niveau du contrôleur les données dynamiques
(paramètres) dans un objet ViewBag afin que le modèle de vue puisse accèder.
Revenez au fichier HelloWorldController.vb et modifiez la méthode Welcome pour ajouter une
valeur de Message et NumTimes à l'objet ViewBag. ViewBag est un objet dynamique, ce qui signifie
que vous pouvez mettre ce que vous voulez en lui ; l'objet ViewBag n'a aucuns propriétés définis
jusqu'à ce que vous mettre quelque chose dedans. Le système de liaison pour le modèle MVC ASP.NET
mappe automatiquement les paramètres nommés (name et numTimes) de la chaine de requête dans
la barre d'adresse aux paramètres dans votre méthode. Le dossier complet de HelloWorldController.vb
ressemble à ceci :
Imports System.Web.Mvc

Namespace Controllers
Public Class HelloWorldController
Inherits Controller

' GET: /HelloWorld


Function Index() As ActionResult
Return View()
End Function

'GET: /HelloWorld/Welcome/
Function Welcome(name As String, Optional numTimes As Integer = 1) As ActionResult
ViewBag.Message = "Hello " & name
ViewBag.NumTimes = numTimes
Return View()
End Function

End Class
End Namespace
L'objet ViewBag contient maintenant des données qui seront transmises automatiquement à
l'affichage. Ensuite, vous avez besoin d'un modèle de vue Bienvenue ! Dans le menu générer,
sélectionnez Générer la Solution (ou Ctrl + Maj + B) pour s'assurer que le projet est compilé. Clic droit
sur le dossier Views\HelloWorld et cliquez sur Ajouter, puis cliquez sur Page de vue MVC 5 avec
disposition (Razor).
Dans la boite de dialogue Spécifier le nom d'élément, entrez Welcome et puis cliquez sur OK.
Dans la boite de dialogue Sélectionner une Page de disposition, acceptez la valeur par défaut
_Layout.vbhtml, puis cliquez sur OK.

Le fichier MvcMovie\Views\HelloWorld\Welcome.vbhtml est créé.


Remplacez la balise dans le fichier Welcome.vbhtml. Vous allez créer une boucle qui dit « Hello
» autant de fois que l'utilisateur dit qu'il se doit. Le dossier complet de Welcome.vbhtml est illustré ci-
dessous.
@Code
ViewBag.Title = "Welcome"
End Code
<h2>Welcome</h2>

<ul>
@For i = 1 To ViewBag.NumTimes
@<li>@ViewBag.Message</li>
Next
</ul>

Exécutez l'application, puis accédez à l'URL suivante :


http://localhost:55532/HelloWorld/Welcome?name=Scott&numtimes=4
Maintenant les données sont tirées de l'URL et transmises au contrôleur en utilisant le modèle
de binding. Le contrôleur empaquète les données dans un objet ViewBag et passe cet objet à la vue.
La vue affiche ensuite les données au format HTML à l'utilisateur.
Dans l'exemple ci-dessus, nous avons utilisé un objet ViewBag pour transmettre les données
du contrôleur à une vue. Plus tard dans ce tutoriel, nous allons utiliser un modèle de vue pour
transférer des données d'un contrôleur à une vue. L'approche du modèle de vue pour passer les
données est généralement beaucoup plus préférable que l'approche de ViewBag. Eh bien, c'était une
sorte de « M » pour le modèle.
Ajout d'un modèle
Dans cette section, vous ajouterez quelques classes afin de gérer les films dans une base de
données. Ces classes seront de la partie « modèle » de l'application ASP.NET MVC.
Vous allez utiliser une technologie d'accès aux données de .NET Framework appelée l'Entity
Framework pour définir et travailler avec ces classes du modèle. Entity Framework (souvent dénommé
"EF") prend en charge un modèle de développement appelé Code First. Code First vous permet de
créer des objets de modèle en utilisant des classes. Vous pourrez ensuite avoir la base de données
créée à la volée depuis vos classes, ce qui active à un workflow de développement très propre et
rapide.

Ajout de classes de modèle


Dans l'Explorateur de solutions, cliquez droit sur le dossier Models, sélectionnez Ajouter, puis
sélectionnez Class.

Entrez le nom de la classe "Movie".


Ajouter les cinq propriétés suivantes à la classe Movie :
Namespace Models
Public Class Movie
Public Property ID As Integer
Public Property Title As String
Public Property ReleaseDate As DateTime
Public Property Genre As String
Public Property Price As Decimal
End Class
End Namespace

En plus des propriétés que vous attendez pour modéliser un film, le champ ID est requis par la
DB comme la clé primaire.
Nous allons utiliser la classe Movie pour représenter des films dans une base de données.
Chaque instance d'un objet Movie correspondra à une ligne dans une table de base de données, et
chaque propriété de la classe Movie sera mappée à une colonne dans la table.
Dans le même fichier, ajoutez la classe Film DBContext suivante :
Imports System.Data.Entity

Namespace Models
Public Class Movie
Public Property ID As Integer
Public Property Title As String
Public Property ReleaseDate As DateTime
Public Property Genre As String
Public Property Price As Decimal
End Class

Public Class MovieDbContext


Inherits DbContext

Public Property Movies As DbSet(Of Movie)


End Class

End Namespace
La classe MovieDBContext représente le Entity Framework contexte de la base de données de
film, qui gère l’extraction, le stockage, et la mettre à jour des instances de classe Movie dans une base
de données. Le MovieDBContext dérive de la classe de base DbContext fournies par Entity Framework.
Afin d'être en mesure de faire référence DbContext et DbSet, vous devez ajouter l'instruction
Imports suivante en haut du fichier :
Imports System.Data.Entity
Vous pouvez le faire en tapant manuellement l'instruction Imports, ou vous pouvez cliquer sur
la ligne rouge squiggly sous DbContext, appuyez sur Maj + Alt + F10 et choisissez Importer
'System.Data.Entity' dans le menu contextuel.

Création d'une chaine de connexion et de travail avec SQL Server


LocalDB
La classe MovieDBContext que vous avez créé gère la tâche de se connecter à la base de
données et le mapping des objets de films à des enregistrements de base de données. Une question
que vous pourriez demander, cependant, est de savoir comment spécifier quelle base de données sera
utilisée. Vous n'avez pas réellement de spécifier quelle base de données à utiliser, Entity Framework
utilise par défaut LocalDB. Dans cette section, nous allons ajouter explicitement une chaine de
connexion dans le fichier web.config de l'application.
SQL Server Express LocalDB
LocalDB est une version allégée du moteur de base de données SQL Server Express qui
commence à la demande et fonctionne en mode utilisateur. LocalDB fonctionne dans un mode
d'exécution spéciale de SQL Server Express qui vous permet de travailler avec des bases de données
enregistrer des fichiers .mdf. En règle générale, les fichiers de base de données LocalDB sont conservés
dans le dossier App_Data d'un projet web.
Par défaut, le Entity Framework regarde dans le fichier web.config pour une chaine de
connexion portant le même nom que la classe de contexte de l'objet (MovieDBContext pour ce projet).
Ouvrez le fichier web.config à la racine de l'application. (Attention il y a un autre fichier web.config
dans le dossier Vues.)

Chercher l'élément <connectionStrings>:

Ajouter la chaine de connexion suivante à l'élément <connectionStrings> dans le fichier


web.config.
<add name="MovieDBContext" connectionString="Data
Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Movies.mdf;Initial
Catalog=Movies;Integrated Security=True" providerName="System.Data.SqlClient" />

L'exemple suivant montre une partie du fichier web.config avec le nouveau connectionstring
ajouté :
<connectionStrings>
<add name="DefaultConnection" connectionString="Data
Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\aspnet-MvcMovie-
20160314123831.mdf;Initial Catalog=aspnet-MvcMovie-20160314123831;Integrated
Security=True" providerName="System.Data.SqlClient" />
<add name="MovieDBContext" connectionString="Data
Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\Movies.mdf;Initial
Catalog=Movies;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>

Les deux chaines de connexion sont très similaires. La première chaine de connexion est
nommée DefaultConnection et elle est utilisé pour la base de données des membres pour contrôler
qui peut accéder à l'application. La chaine de connexion que vous avez ajoutée spécifie une base de
données LocalDB nommée Movie.mdf situé dans le dossier App_Data.
Le nom de la chaine de connexion doit correspondre au nom de la classe DbContext.
Public Class MovieDbContext
Inherits DbContext

Public Property Movies As DbSet(Of Movie)


End Class

Vous pouvez nommer la base de données avec le nom que vous voulez, tant qu'il a le suffixe
.mdf. Par exemple, nous pourrions nommer la base de données MyFilms.mdf.
Vous allez construire une nouvelle classe de contrôleur de film que vous pouvez utiliser pour
afficher les données de films et de permettre aux utilisateurs de créer de nouvelles listes de films.
Avant de faire ceci il faut régénère le projet : Build > Générez MVCMovie (Sinon vous
obtiendrez une erreur dans les sections suivantes). Nous avons finalement ajouté un modèle à votre
application MVC.

Scaffolding un contrôleur
Dans l'Explorateur de solutions, cliquez-droit sur le dossier Controllers> Ajouter> Contrôleur.
Dans la boite de dialogue Ajouter un modèle automatique, appuyez sur Contrôleur MVC 5
avec vues, en utilisant Entity Framework > Ajouter.

Remplissez la boite de dialogue Ajouter un contrôleur :


 Classe de modèle : Movie (MvcMovie.Models)
 Classe de contexte de données : MovieDbContext (MvcMovie.Models)
 Vues : Gardez les valeurs par défaut de chaque option cochée
 Nom du contrôleur : Gardez la valeur par défaut « MoviesController »
 Cliquer sur Ajouter

Le moteur de visuel studio de scaffolding crée les éléments suivants :


 Un contrôleur (MoviesController.vb)
 Un répertoire Views\Movies
 Les fichiers de vue Razor : Create, Delete, Details, Edit et Index
Visual Studio crée automatiquement le CRUD (créer, lire, mettre à jour et supprimer) les
méthodes d'action et des vues pour vous (la création automatique de CRUD méthodes d'action et des
vues est connu sous le nom Scaffolding). Vous aurez bientôt une application web entièrement
fonctionnel qui vous permet de créer, liste, modifier et supprimer des entités de Movies.
Exécutez l'application et parcourir au contrôleur de Movies en ajoutant /Movies à l'URL dans
la barre d'adresse de votre navigateur. Parce que l'application repose sur le routage par défaut (défini
dans le fichier App_Start\RouteConfig.vb), la demande navigateur http://localhost:55532/Movies est
acheminé par défaut à la méthode d'action Index du contrôleur Movies. En d'autres termes, la requête
http://localhost:55532/Movies est effectivement la même requête
http://localhost:55532/Movies/Index. Le résultat est une liste vide de films, parce que vous ne l'avez
pas encore ajouté.

Création d'un film


Sélectionnez le lien Create New. Entrez quelques détails sur un film et puis cliquez sur le
bouton Create.
Remarque : En fonction de vos paramètres régionaux, vous ne pouvez pas être en mesure
d'entrer des points ou des virgules décimales dans le champ Price. Pour soutenir la validation jQuery
pour les paramètres régionaux non anglais qui utilisent une virgule (",") pour un point décimal, et les
formats de date non US-anglais, vous devez inclure globalize.js et vos spécifiques au fichier
cultures/globalize.cultures.js (à partir https://github.com/jquery/globalize) et JavaScript pour utiliser
Globalize.parseFloat. L’utilisation de ceci sera comment faire plus tard. Pour l'instant, il suffit d'entrer
des nombres entiers comme 10.
Le clique sur le bouton Create New provoque l’affichage du formulaire sur le serveur, où
l'information de film est enregistrée dans la base de données. Vous êtes alors redirigé vers le URL
/Movies, où vous pouvez voir le film nouvellement créé dans la liste.
Créer plus d'entrées. Essayez les liens de Edit, Details et Delete, qui sont tous fonctionnels.

Examiner le code généré


Ouvrez le fichier Controllers\MoviesController.vb et examiner la méthode Index générée. Une
partie du contrôleur de Movies avec la méthode index est présentée ci-dessous.
Namespace Controllers
Public Class MoviesController
Inherits System.Web.Mvc.Controller

Private db As New MovieDbContext

' GET: Movies


Function Index() As ActionResult
Return View(db.Movies.ToList())
End Function

Une demande au contrôleur Movies renvoie toutes les entrées de la table des Movies, puis
transmet les résultats à la vue de l'index. La ligne suivante de la classe MoviesController instancie un
contexte de base de données de Movie, comme décrit précédemment. Vous pouvez utiliser le contexte
de base de données Movie pour interroger, modifier et supprimer des films.
Private db As New MovieDbContext
Modèles fortement typées et le mots-clé @ModelType
Plus tôt dans ce tutoriel, vous avez vu comment un contrôleur peut transmettre des données
ou des objets à un modèle de vue en utilisant l'objet ViewBag. Le ViewBag est un objet dynamique qui
fournit un moyen à liaison tardive pratique pour transmettre des informations à une vue.
MVC offre également la possibilité de passer des objets fortement typés à une vue. Cette
approche fortement typée permet de mieux vérifier votre code et d’utiliser IntelliSense dans l'éditeur
Visual Studio lors de la compilation. Le mécanisme de Scaffolding dans Visual Studio utilisé cette
approche (qui est, le passage d'un modèle fortement typé) avec la classe MoviesController et les
Templates de vues quand il a créé les méthodes et les vues.
Dans le fichier Controllers\MoviesController.vb, examine la méthode générée Details. La
méthode Details est illustré ci-dessous.
' GET: Movies/Details/5
Function Details(ByVal id As Integer?) As ActionResult
If IsNothing(id) Then
Return New HttpStatusCodeResult(HttpStatusCode.BadRequest)
End If
Dim movie As Movie = db.Movies.Find(id)
If IsNothing(movie) Then
Return HttpNotFound()
End If
Return View(movie)
End Function

Le paramètre id est généralement passé en tant que données de routage, par exemple
http://localhost:55532/Movies/Details/1 définiront le contrôleur au contrôleur de Movies, l'action à
Details et l'identifiant à 1. Vous pouvez également passer dans le id avec la chaine de requête comme
suit :
http://localhost:55532/movies/details?id=1
Si un film est trouvé, une instance du modèle de Movie est passé à la vue Details:
Return View(movie)

Examinez le contenu du fichier Views\Movies\Details.vbhtml :


@ModelType MvcMovie.Models.Movie
@Code
ViewData("Title") = "Details"
End Code

<h2>Details</h2>

<div>
<h4>Movie</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(Function(model) model.Title)
</dt>

<dd>
@Html.DisplayFor(Function(model) model.Title)
</dd>

<dt>
@Html.DisplayNameFor(Function(model) model.ReleaseDate)
</dt>

<dd>
@Html.DisplayFor(Function(model) model.ReleaseDate)
</dd>
<dt>
@Html.DisplayNameFor(Function(model) model.Genre)
</dt>

<dd>
@Html.DisplayFor(Function(model) model.Genre)
</dd>

<dt>
@Html.DisplayNameFor(Function(model) model.Price)
</dt>

<dd>
@Html.DisplayFor(Function(model) model.Price)
</dd>

</dl>
</div>
<p>
@Html.ActionLink("Edit", "Edit", New With { .id = Model.ID }) |
@Html.ActionLink("Back to List", "Index")
</p>

En incluant une déclaration de type @ModelType au début du fichier Template vue, vous
pouvez spécifier le type d'objet que la vue attend. Lorsque vous avez créé le contrôleur de Movies,
Visual Studio automatiquement inclus la déclaration suivante de @ModelType en haut du fichier
Details.vbhtml en se basant sur le modèle de la classe que vous avez sélectionné lors de l'ajout du
contrôleur :

@ModelType MvcMovie.Models.Movie

Cette directive @ModelType vous permet d'accéder au film que le contrôleur passé à la vue à
l'aide d'un objet de modèle qui est fortement typée. Par exemple, dans la vue Details.vbhtml, le code
passe chaque champ de film pour les Helpers HTML DisplayNameFor et DisplayFor avec l'objet du
modèle fortement typé. Les méthodes Create et Edit et les vues templates passent également un objet
de modèle de film.
Examinez la vue Index.vbhtml et la méthode Index dans le contrôleur MoviesController.vb.
Remarquez comment le code crée un objet de la liste quand il appelle la méthode View dans la
méthode d'action Index. Ainsi, Le code passe cette liste de films à partir de la méthode d'action Index
à la vue.
Function Index() As ActionResult
Return View(db.Movies.ToList())
End Function
Lorsque vous avez créé le contrôleur de Movie, Visual Studio inclus automatiquement la
déclaration @ModelType à la partie supérieure du fichier Index.vbhtml :
@ModelType IEnumerable(Of MvcMovie.Models.Movie)
Cette directive @ModelType, vous permet d'accéder à la liste des films que le contrôleur
transmis à la vue à l'aide d'un objet modèle qui est fortement typée. Par exemple, dans la vue
Index.vbhtml, le code itère sur les films en faisant une instruction For Each sur l’objet fortement typé
du Modèle :
@For Each item In Model
@<tr>
<td>
@Html.DisplayFor(Function(modelItem) item.Title)
</td>
<td>
@Html.DisplayFor(Function(modelItem) item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(Function(modelItem) item.Genre)
</td>
<td>
@Html.DisplayFor(Function(modelItem) item.Price)
</td>
<td>
@Html.ActionLink("Edit", "Edit", New With {.id = item.ID }) |
@Html.ActionLink("Details", "Details", New With {.id =
item.ID }) |
@Html.ActionLink("Delete", "Delete", New With {.id = item.ID
})
</td>
</tr>
Next
Parce que l’objet modèle est fortement typé (comme étant l’objet IEnumerable<Movie>),
chaque objet item dans la boucle est typé comme étant Movie. Ceci vous accorde plusieurs avantages
tels que : l’obtention des vérifications lors de la compilation du code et le support complet de
l’IntelliSense dans l'éditeur de code :

Travailler avec SQL Server LocalDB


Entity Framework Code First a détecté que la chaine de connexion de base de données qui a
été fourni pointe vers une base de données nommé Movies et qui n'existait pas encore. Ainsi
l’approche code First créé la base de données automatiquement. Vous pouvez vérifier qu'il a été créé
en regardant dans le dossier App_Data. Si vous ne voyez pas le fichier Movies.mdf, cliquez sur le
bouton Afficher tous les fichiers dans la barre d'outils de l’Explorateur de solutions, cliquez sur le
bouton Refresh, puis développez le dossier App_Data.
Double-cliquez sur Movies.mdf pour ouvrir SERVER EXPLORER, puis développez le dossier
tables pour voir la table Movies. Notez l'icône de clé à côté de ID. Par défaut, EF fera de la propriété ID
une clé primaire.
Cliquez droit sur la table Movies et sélectionnez Show Table Data pour voir les données que
vous avez créé.

Cliquez droit sur la table Movies et sélectionnez Open Table definition afin de voir la structure
de table que l’Entity Framework Code First a créé pour vous.
Remarquez comment le schéma de la Table Movies se liée à la classe Movie que vous avez
créé précédemment. L’Entity Framework Code First créé automatiquement ce schéma pour vous en
fonction de votre classe Movie.
Lorsque vous aurez terminé, fermer la connexion en cliquant à droite de MovieDBContext et
en sélectionnant Fermer la connexion. (Si vous ne fermez pas la connexion, vous pourriez obtenir une
erreur la prochaine fois que vous exécutez le projet).

Vous avez maintenant une base de données et les pages pour afficher, modifier, mettre à jour
et supprimer des données.
Examinant les méthodes Edit et la vue Edit
Vous allez examiner la méthode d'action généré Edit et sa vue associée pour le contrôleur
Movie. Mais tout d'abord nous allons modifier le modèle afin de mieux afficher la date de sortie.
Ouvrez le fichier Models\Movie.vb et ajoutez les lignes surbrillance ci-dessous :
Imports System.ComponentModel.DataAnnotations
Imports System.Data.Entity

Namespace Models
Public Class Movie
Public Property ID As Integer
Public Property Title As String
<Display(Name:="Release Date")>
<DataType(DataType.Date)>
<DisplayFormat(DataFormatString:="{0:yyyy-MM-dd}",
ApplyFormatInEditMode:=True)>
Public Property ReleaseDate As DateTime
Public Property Genre As String
Public Property Price As Decimal
End Class

Public Class MovieDbContext


Inherits DbContext

Public Property Movies As DbSet(Of Movie)


End Class
End Namespace

Vous pouvez également faire la culture de date spécifique comme ceci :


<DisplayFormat(DataFormatString:="{0:d}", ApplyFormatInEditMode:=True)>
Nous couvrirons DataAnnotations plus-tard. L'attribut Display spécifie ce qu'il faut afficher
pour le nom d'un champ (en l'occurrence "Release Date" au lieu de « ReleaseDate»). L'attribut
DataType spécifie le type des données, dans ce cas c'est une date, pour les moment les informations
stockées dans le champ n'est pas affiché. L'attribut DisplayFormat est nécessaire pour un bug dans le
navigateur de Chrome qui restitue les formats de date incorrecte.
Exécutez l'application et naviguez vers le contrôleur Movies. Maintenez le pointeur de la souris
sur un lien Edit pour voir l'URL à lequel il fait référence.
Le lien Edit a été généré par la méthode Html.ActionLink de le vue Views\Movies\Index.vbhtml
:

@Html.ActionLink("Edit", "Edit", New With {.id = item.ID }) |

L'objet Html est une aide (Helper) qui exposé en utilisant une propriété de la classe de base
System.Web.Mvc.WebViewPage. La méthode ActionLink du Helper facilite la génération
dynamiquement des liens hypertexte HTML qui pointent vers des méthodes d'action des contrôleurs.
Le premier argument à la méthode ActionLink est le texte rendu en lien hypertexte (par exemple,
<a>Edit Me</a>). Le second argument est le nom de la méthode d'action à appeler (dans ce cas,
l'action Edit). Le dernier argument est un objet anonyme qui génère les données de parcours (dans ce
cas, l'ID de 4).
Le lien généré montré dans l'image précédente est http://localhost:55532/films/Edit/3.
L'itinéraire par défaut (créé en App_Start\RouteConfig.vb) prend le modèle d'URL
{controller}/{action}/{id}. Par conséquent, ASP.NET traduit l’URL http://localhost: 55532/films/Edit/3
par une requête à la méthode d'action Edit du contrôleur Movies avec le paramètre ID qui est vaut 3.
Examinez le code suivant dans le fichier App_Start\RouteConfig.vb. La méthode MapRoute est utilisé
pour router les requêtes HTTP vers le bon contrôleur, en choisissant la méthode d'action et en
fournissant le paramètre d'ID qui est facultatif. La méthode MapRoute est également utilisée par les
HtmlHelpers comme ActionLink pour générer des URL en fournissant le contrôleur, la méthode
d'action et des données de parcours.
Public Module RouteConfig
Public Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")

routes.MapRoute(
name:="Default",
url:="{controller}/{action}/{id}",
defaults:=New With {.controller = "Home", .action = "Index", .id =
UrlParameter.Optional}
)
routes.MapRoute(
name:="Hello",
url:="{controller}/{action}/{name}/{id}"
)

End Sub
End Module

Vous pouvez également passer des paramètres de méthode d'action à l'aide d'une chaine de
requête. Par exemple, l'URL http://localhost:55532/Movies/Edit?ID=3 passe également le paramètre
ID de 3 pour la méthode d'action Edit du contrôleur Movies.
Ouvrir le contrôleur Movies. Les deux méthodes d'action Edit figurent ci-dessous.
' GET: Movies/Edit/5
Function Edit(ByVal id As Integer?) As ActionResult
If IsNothing(id) Then
Return New HttpStatusCodeResult(HttpStatusCode.BadRequest)
End If
Dim movie As Movie = db.Movies.Find(id)
If IsNothing(movie) Then
Return HttpNotFound()
End If
Return View(movie)
End Function
' POST: Movies/Edit/5
'Afin de déjouer les attaques par sur-validation, activez les propriétés
spécifiques que vous voulez lier. Pour
'plus de détails, voir http://go.microsoft.com/fwlink/?LinkId=317598.
<HttpPost()>
<ValidateAntiForgeryToken()>
Function Edit(<Bind(Include:="ID,Title,ReleaseDate,Genre,Price")> ByVal
movie As Movie) As ActionResult
If ModelState.IsValid Then
db.Entry(movie).State = EntityState.Modified
db.SaveChanges()
Return RedirectToAction("Index")
End If
Return View(movie)
End Function

Noter que la deuxième méthode d'action Edit est précédée de l'attribut HttpPost. Cet attribut
spécifie que cette surcharge de la méthode Edit est appelée uniquement pour les requêtes POST. Vous
pouvez appliquer l'attribut HttpGet à la première méthode Edit, mais ce n'est pas nécessaire, parce
que c'est la valeur par défaut. L'attribut Bind est un autre mécanisme de sécurité important qui
empêche les pirates de trop poster des données à votre modèle. Vous ne devez inclure que les
propriétés que vous souhaitez modifier dans l'attribut Bind. Dans ce modèle simple utilisé dans ce
tutoriel, nous engagerons toutes les données du modèle. L'attribut ValidateAntiForgeryToken est
utilisé pour prévenir la falsification d'une demande et est jumelé avec @Html.AntiForgeryToken() dans
le fichier de vue Edit (Views\Movies\Edit.vbhtml), une partie est illustrée ci-dessous :
@ModelType MvcMovie.Models.Movie
@Code
ViewData("Title") = "Edit"
End Code

<h2>Edit</h2>

@Using (Html.BeginForm())
@Html.AntiForgeryToken()

@<div class="form-horizontal">
<h4>Movie</h4>
<hr />
@Html.ValidationSummary(True, "", New With { .class = "text-danger" })
@Html.HiddenFor(Function(model) model.ID)

<div class="form-group">
@Html.LabelFor(Function(model) model.Title, htmlAttributes:= New With {
.class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(Function(model) model.Title, New With {
.htmlAttributes = New With { .class = "form-control" } })
@Html.ValidationMessageFor(Function(model) model.Title, "", New With
{ .class = "text-danger" })
</div>
</div>

@Html.AntiForgeryToken() génère un jeton masqué d'anti-contrefaçon dans le formulaire qui


doit correspondre dans la méthode Edit du contrôleur Movies. Ceci afin de se prévenir contre des
attaque de type Cross-site request forgery (XSRF ou CSRF).
La méthode Edit de HttpGet prend le paramètre ID de film, cherche un film à l'aide de la
méthode Find de l’Entity Framework et retourne le film sélectionné à la vue Edit. Si un film est
introuvable, HttpNotFound est retourné. Lorsque le système de scaffolding créé la vue Edit, il examine
la classe Movie et il crée le code pour restituer des éléments <label> et <input> pour chaque propriété
de la classe. L'exemple suivant montre l'affichage de Edit qui a été généré par le système de scaffolding
de visual studio :
@ModelType MvcMovie.Models.Movie
@Code
ViewData("Title") = "Edit"
End Code

<h2>Edit</h2>

@Using (Html.BeginForm())
@Html.AntiForgeryToken()

@<div class="form-horizontal">
<h4>Movie</h4>
<hr />
@Html.ValidationSummary(True, "", New With { .class = "text-danger" })
@Html.HiddenFor(Function(model) model.ID)

<div class="form-group">
@Html.LabelFor(Function(model) model.Title, htmlAttributes:= New With {
.class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(Function(model) model.Title, New With {
.htmlAttributes = New With { .class = "form-control" } })
@Html.ValidationMessageFor(Function(model) model.Title, "", New With
{ .class = "text-danger" })
</div>
</div>

<div class="form-group">
@Html.LabelFor(Function(model) model.ReleaseDate, htmlAttributes:= New
With { .class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(Function(model) model.ReleaseDate, New With {
.htmlAttributes = New With { .class = "form-control" } })
@Html.ValidationMessageFor(Function(model) model.ReleaseDate, "",
New With { .class = "text-danger" })
</div>
</div>

<div class="form-group">
@Html.LabelFor(Function(model) model.Genre, htmlAttributes:= New With {
.class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(Function(model) model.Genre, New With {
.htmlAttributes = New With { .class = "form-control" } })
@Html.ValidationMessageFor(Function(model) model.Genre, "", New With
{ .class = "text-danger" })
</div>
</div>

<div class="form-group">
@Html.LabelFor(Function(model) model.Price, htmlAttributes:= New With {
.class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(Function(model) model.Price, New With {
.htmlAttributes = New With { .class = "form-control" } })
@Html.ValidationMessageFor(Function(model) model.Price, "", New With
{ .class = "text-danger" })
</div>
</div>

<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
End Using

<div>
@Html.ActionLink("Back to List", "Index")
</div>

@Section Scripts
@Scripts.Render("~/bundles/jqueryval")
End Section

Remarquez comment le modèle d'affichage a une déclaration de @model


MvcMovie.Models.Movie en haut du fichier, cette option indique que la vue attend le modèle pour le
modèle d'affichage de type Movie.
Le code structure utilise plusieurs méthodes d'assistance pour rationaliser le balisage HTML.
Le helper Html.LabelFor affiche le nom du champ ("Title", "Date de sortie", "Genre" ou "Prix"). Le
helper Html.EditorFor restitue un élément <input> de HTML. Le helper Html.ValidationMessageFor
affiche des messages de validation associés à cette propriété.
Exécutez l'application et accédez à l'URL /Movies. Cliquez sur un lien Edit. Dans le navigateur,
affichez le code source de la page. Ci-dessous le code HTML du formulaire.
<form action="/Movies/Edit?ID=3" method="post">
<input name="__RequestVerificationToken" type="hidden"
value="hcnE5fWGPpFxQBshcjpw6uirYXpxjMLaKwpxZndVKTj4p-o9ByjdZXRrPV-
LTp5aip_FjCEah3HK2RJre5VGoYL-SvPKrnNciJ6vhQxRXls1" /> <div class="form-
horizontal">
<h4>Movie</h4>
<hr />

<input data-val="true" data-val-number="The field ID must be a number."


data-val-required="Le champ ID est requis." id="ID" name="ID" type="hidden"
value="3" />

<div class="form-group">
<label class="control-label col-md-2" for="Title">Title</label>
<div class="col-md-10">
<input class="form-control text-box single-line" id="Title"
name="Title" type="text" value="Example 2" />
<span class="field-validation-valid text-danger" data-valmsg-
for="Title" data-valmsg-replace="true"></span>
</div>
</div>

<div class="form-group">
<label class="control-label col-md-2" for="ReleaseDate">Release
Date</label>
<div class="col-md-10">
<input class="form-control text-box single-line" data-val="true"
data-val-date="The field Release Date must be a date." data-val-required="Le champ
Release Date est requis." id="ReleaseDate" name="ReleaseDate" type="date"
value="2014-02-28" />
<span class="field-validation-valid text-danger" data-valmsg-
for="ReleaseDate" data-valmsg-replace="true"></span>
</div>
</div>

<div class="form-group">
<label class="control-label col-md-2" for="Genre">Genre</label>
<div class="col-md-10">
<input class="form-control text-box single-line" id="Genre"
name="Genre" type="text" value="Action" />
<span class="field-validation-valid text-danger" data-valmsg-
for="Genre" data-valmsg-replace="true"></span>
</div>
</div>

<div class="form-group">
<label class="control-label col-md-2" for="Price">Price</label>
<div class="col-md-10">
<input class="form-control text-box single-line" data-val="true"
data-val-number="The field Price must be a number." data-val-required="Le champ
Price est requis." id="Price" name="Price" type="text" value="22,00" />
<span class="field-validation-valid text-danger" data-valmsg-
for="Price" data-valmsg-replace="true"></span>
</div>
</div>

<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
</form>

Les éléments <input> sont dans un élément <form> de HTML dont l'attribut action a la valeur
post à l'URL /Movies/Edit. Les données de formulaire seront affichées sur le serveur lorsqu'un clic est
effectué sur le bouton Save. La seconde ligne montre le jeton caché XSRF généré par l'appel de
@Html.AntiForgeryToken().

Traitement de la demande POST


Le Code suivant affiche la version HttpPost de la méthode d'action Edit.
<HttpPost()>
<ValidateAntiForgeryToken()>
Function Edit(<Bind(Include:="ID,Title,ReleaseDate,Genre,Price")> ByVal
movie As Movie) As ActionResult
If ModelState.IsValid Then
db.Entry(movie).State = EntityState.Modified
db.SaveChanges()
Return RedirectToAction("Index")
End If
Return View(movie)
End Function

L'attribut ValidateAntiForgeryToken valide le jeton XSRF généré par l'appel de


@Html.AntiForgeryToken() dans la vue.
Le modèle Binder de ASP.NET MVC prend les valeurs du formulaire affiché et crée un objet de
Movie qui est passé comme paramètre nommée movie. La méthode ModelState.IsValid vérifie que
les données fournies dans le formulaire peuvent servir afin de modifier (éditer ou mise à jour) un objet
Movie. Si les données sont valides, les données du film sont enregistrées dans la collection Movies de
l’objet db (instance de MovieDBContext). Les nouvelles données sont enregistrées dans la base de
données en appelant la méthode SaveChanges de MovieDBContext. Après avoir sauvegardé les
données, le code redirige l'utilisateur vers la méthode d'action Index de la classe MoviesController,
qui affiche la liste des films, y compris les changements que vient d’être appliqués.
Dès la validation côté client, l’application détermine les valeurs d'un champ qui ne sont pas
valides et affiche un message d'erreur. Si vous désactivez JavaScript, vous n'aurez pas la validation côté
client, mais le serveur détecte que les valeurs envoyées ne sont pas valides, et les valeurs de la forme
vont être réaffichées avec des messages d'erreur. Plus tard dans le tutoriel, nous examinons validation
plus en détail.
Les helpers Html.ValidationMessageFor dans le modèle d'affichage Edit.vbhtml prendre soin
d'afficher les messages d'erreur appropriées.
Toutes les méthodes HttpGet suivent un modèle similaire. Ils identifient un objet film (ou une
liste d'objets, dans le cas Index) et passent le modèle à la vue. La méthode Create passe un objet film
vide à la vue de la création. Toutes les méthodes qui créer, modifier, supprimer ou modifient des
données dans le cas contraire va le faire dans la surcharge HttpPost de la méthode. La modification
des données dans une méthode HTTP GET engendre un risque pour la sécurité. La modification de
données dans une méthode GET viole également les meilleures pratiques HTTP et le modèle
architectural de reste, qui stipule que les requêtes GET ne devraient pas changer l'état de votre
application. En d'autres termes, une opération GET doit être une opération sécuritaire qui n'a aucuns
effets secondaires et ne modifie pas vos données persistantes.
Noter que : afin de supporter la validation de jQuery pour les paramètres régionaux non anglais
qui utilisent une virgule («, ») pour un point décimal et les formats de date non US-anglais, vous devez
inclure le fichier globalize.js et votre fichier spécifique cultures/globalize.cultures.js (depuis
https://github.com/jquery/globalize) et l’utilisation de JavaScript pour utiliser Globalize.parseFloat.
Vous pouvez obtenir la validation de non-anglais jQuery de NuGet.
1. Dans le menu Outils, cliquez sur Gestionnaire de Package NuGet et puis cliquez sur Gérer
les Packages NuGet de Solution.

2. Dans le volet gauche, sélectionnez Online ou Parcourir. (Voir l'image ci-dessous).


3. Dans la zone de saisie de recherche, entrez Globalize.

Cliquez sur installer puis Ok. Le fichier Scripts\globalize.js sera ajouté à votre projet. Le
dossier Scripts\globalize\ contient de nombreux fichiers JavaScript de culture.
Le code suivant montre les modifications dans le fichier Views\Movies\Edit.vbhtml :
@Section Scripts
@Scripts.Render("~/bundles/jqueryval")

<script src="~/Scripts/globalize/globalize.js"></script>
<script
src="~/Scripts/globalize/cultures/globalize.culture.@(System.Threading.Thread.Curren
tThread.CurrentCulture.Name).js"></script>
<script>
$.validator.methods.number = function (value, element) {
return this.optional(element) ||
!isNaN(Globalize.parseFloat(value));
}
$(document).ready(function () {

Globalize.culture('@(System.Threading.Thread.CurrentThread.CurrentCulture.Name)');
});
</script>
<script>
jQuery.extend(jQuery.validator.methods, {
range: function (value, element, param) {
//Use the Globalization plugin to parse the value
var val = Globalize.parseFloat(value);
return this.optional(element) || (
val >= param[0] && val <= param[1]);
}
});
$.validator.methods.date = function (value, element) {
return this.optional(element) ||
Globalize.parseDate(value) ||
Globalize.parseDate(value, "yyyy-MM-dd");
}
</script>
}

End Section

Pour éviter de répéter ce code dans chaque vue d'édition, vous pouvez la déplacer vers le
fichier de mise en page.
Comme une solution temporaire, si vous ne pouvez pas obtenir validation travaillant dans vos
paramètres régionaux, vous pouvez forcer votre ordinateur à utiliser en anglais américain ou vous
pouvez désactiver le JavaScript dans votre navigateur. Pour forcer votre ordinateur à utiliser en anglais
américain, vous pouvez ajouter l'élément globalization dans le fichier web.config de projets racine. Le
code suivant montre l'élément globalization avec la culture mises à l'anglais des États-Unis.
<system.web>
<globalization culture ="en-US" />
<!--elements removed for clarity-->
</system.web>
Ajout d'une méthode de recherche et sa vue
Dans cette section, vous allez ajouter des capacités de recherche de la méthode d'action
Index qui vous permet de rechercher des films par genre, ou nom.

Mise à jour de la forme Index


Commencez par mettre à jour la méthode d'action Index à la classe existante
MoviesController. Voici le code :
' GET: Movies
Function Index(ByVal searchString As String) As ActionResult
Dim movies = From m In db.Movies Select m
If Not String.IsNullOrEmpty(searchString) Then
movies = movies.Where(Function(movie) movie.Title.Contains(searchString))
End If
Return View(movies)
End Function

La première ligne de la méthode Index crée la requête LINQ suivante pour sélectionner les
films :
Dim movies = From m In db.Movies Select m

La requête est définie à ce stade, mais n'a pas encore été exécutée sur la base de données.
Si le paramètre searchString contient une chaine, la requête est modifiée pour filtrer sur la
valeur de la chaine de recherche, en utilisant le code suivant :
If Not String.IsNullOrEmpty(searchString) Then
movies = movies.Where(Function(movie) movie.Title.Contains(searchString))
End If

Le code Function(movie) ci-dessus est une Expression Lambda. Lambdas sont utilisés dans les
méthode fondée sur les requêtes LINQ en tant qu'arguments aux méthodes d'opérateur de requête
standard telles que la méthode Where utilisé dans le code ci-dessus. Les requêtes LINQ ne sont pas
exécutées lorsqu'elles sont définies ou lorsqu'elles sont modifiées en appelant une méthode telle que
Where ou OrderBy. Au lieu de cela, l’exécution de la requête est différée, ce qui signifie que
l'évaluation d'une expression est retardée jusqu'à ce que sa valeur réalisée soit effectivement
parcourue ou la méthode ToList est appelée. Dans une recherche simple, la requête est exécutée dans
la vue Index.vbhtml. Note : la méthode Contains est exécutée sur la base de données quand vous LINQ
aux entites, et n’ont pas dans le code vb précédent. Dans la base de données, Contains mappe vers
l’opérateur LIKE de SQL, qui est insensible à la casse.
Maintenant vous pouvez mettre à jour la vue Index qui affiche le formulaire à l'utilisateur.
Exécutez l'application et naviguez jusqu'à /Movies/Index. Ajoutez à l'URL une chaine de
requête comme ?searchString=xe. Les films filtrés sont affichés.
Si vous modifiez la signature de la méthode de Index pour avoir un paramètre nommé id, le
paramètre id correspondra à l'espace réservé {id} de la route par défaut définie dans le fichier
App_Start\RouteConfig.vb.
{controller}/{action}/{id}
La méthode originale de Index ressemble à ceci :
' GET: Movies
Function Index(ByVal searchString As String) As ActionResult
Dim movies = From m In db.Movies Select m
If Not String.IsNullOrEmpty(searchString) Then
movies = movies.Where(Function(movie) movie.Title.Contains(searchString))
End If
Return View(movies)
End Function

La méthode modifiée de Index se présente comme suit :


' GET: Movies
Function Index(ByVal id As String) As ActionResult
Dim searchString = id
Dim movies = From m In db.Movies Select m
If Not String.IsNullOrEmpty(searchString) Then
movies = movies.Where(Function(movie) movie.Title.Contains(searchString))
End If
Return View(movies)
End Function
Vous pouvez maintenant passer le titre de la recherche en tant que données de parcours (un
segment d'URL) au lieu d’une valeur de la chaine de la requête.

Toutefois, vous ne pouvez pas attendre aux utilisateurs de modifier l'URL à chaque fois qu'ils
veulent chercher d'un film. Alors maintenant, vous allez ajouter à l'interface utilisateur - pour les aider
- un filtre sur les films. Si vous avez changé la signature de la méthode Index pour tester comment
passer le paramètre ID de route est lié, alors il faut revenir à la précédente version afin que votre
méthode Index prend un paramètre de chaine nommée searchString :
' GET: Movies
Function Index(ByVal searchString As String) As ActionResult
Dim movies = From m In db.Movies Select m
If Not String.IsNullOrEmpty(searchString) Then
movies = movies.Where(Function(movie) movie.Title.Contains(searchString))
End If
Return View(movies)
End Function

Ouvrez le fichier Views\Movies\Index.vbhtml et juste après @Html.ActionLink("Create New",


"Create"), ajoutez la balise de formulaire ci-dessous :
<p>
@Html.ActionLink("Create New", "Create")

@Using Html.BeginForm("Index", "Movies", FormMethod.Post)


@<p>Title: @Html.TextBox("SearchString") <br />
<input type="submit" value="Filter" />
</p>
End Using
</p>

Le helper Html.BeginForm crée une balise ouvrante <form>. Le helper Html.BeginForm


provoque une action du formulaire sur lui-même lorsque l'utilisateur soumet le formulaire en cliquant
sur le bouton Filtrer.
Visual Studio 2013 a une belle amélioration lors de l'affichage et de la modification des fichiers
de vue. Lorsque vous exécutez l'application avec un fichier de vue ouvert, Visual Studio 2013 appelle
la méthode d'action du contrôleur correspondante pour afficher la vue.

Avec la vue Index ouvert dans Visual Studio (tel qu'illustré dans l'image ci-dessus), appuyez sur
Ctr F5 ou F5 pour exécuter l'application et puis essayez de rechercher un film.
Il n'y a aucune surcharge HttpPost de la méthode de Index. Vous n'avez pas besoin, parce que
la méthode n'a pas modifié l'état de l'application, juste un filtrage des données.
Vous pourriez ajouter la surcharge HttpPost de la méthode Index suivante. Dans ce cas,
d'action appelante correspondrait à la surcharge HttpPost de la méthode Index, et la méthode Index
irait comme le montre l'image ci-dessous.
<HttpPost>
Function Index(ByVal fc As FormCollection, ByVal searchString As String)
Return "<h3> From &lt;HttpPost&gt;Index: " & searchString & "</h3>"
End Function

Toutefois, même si vous ajoutez cette version HttpPost de la méthode Index, il y a une
limitation dans comment tous ceci a été mis en place. Imaginez que vous voulez mettre en signet une
recherche particulière ou vous voulez envoyer un lien à vos amis qu'ils peuvent cliquer afin de voir la
même liste filtrée des films. Notez que l'URL de la requête HTTP POST est le même que l'URL de la
requête GET (localhost:xxxxx/Movies/Index)--il n'y a aucune information de la recherche dans l'URL
elle-même. Maintenant, les informations de chaine de recherche sont envoyées au serveur comme
une valeur de champ de formulaire. Cela signifie que vous ne pouvez pas saisir cette information de
recherche pour favori, ou envoyer à vos amis dans une URL.
La solution est d'utiliser une surcharge de BeginForm qui spécifie que la requête POST devrait
ajouter les informations de recherche à l'URL et qu'il doit être acheminé vers la version HttpGet de la
méthode Index. Remplacez la méthode BeginForm sans paramètre existante par le balisage suivant :
@Using Html.BeginForm("Index", "Movies", FormMethod.Get)
Maintenant lorsque vous soumettez une recherche, l'URL contient une chaine de requête de
recherche. La recherche servira également à la surcharge HttpGet de la méthode d'action Index, même
si vous avez une surcharge HttpPost méthode Index.

Ajout de recherche par Genre


Si vous avez ajouté la version HttpPost de la méthode de Index, supprimer la maintenant.
Ensuite, vous allez ajouter une fonctionnalité pour permettre aux utilisateurs de rechercher
des films par genre. Remplacez la méthode Index par le code suivant :
Function Index(ByVal movieGenre As String, ByVal searchString As String)
Dim genreList As New List(Of String)
Dim genreQuery = From m In db.Movies
Order By m.Genre
Select m.Genre

genreList.AddRange(genreQuery.Distinct)

ViewBag.movieGenre = New SelectList(genreList)


Dim movies = From m In db.Movies
Select m

If Not String.IsNullOrEmpty(searchString) Then


movies = movies.Where(Function(m) m.Title.Contains(searchString))
End If

If Not String.IsNullOrEmpty(movieGenre) Then


movies = movies.Where(Function(m) m.Genre.Equals(movieGenre))
End If
Return View(movies)
End Function

Cette version de la méthode Index prend un paramètre supplémentaire, à savoir movieGenre.


Les premières lignes de code créent un objet de type List pour contenir les genres de film de la base
de données.
Le code suivant est une requête LINQ qui récupère tous les genres de la base de données.
Dim genreQuery = From m In db.Movies
Order By m.Genre
Select m.Genre

Le code utilise la méthode AddRange de la collection de générique List pour ajouter tous les
genres distincts à la liste. (Sans le modificateur Distinct, ils s'ajouteraient des genres en double — par
exemple, le genre « Action » s'ajouterais deux fois dans notre échantillon). Puis, le code stocke la liste
des genres dans l'objet ViewBag.movieGenre. Ceci stocke la catégorie des données (tel que le genre
du film) comme un objet SelectList dans un ViewBag, puis accéder à la catégorie de données dans une
zone de liste déroulante est une approche classique pour les applications MVC.
Le code suivant montre la vérification du paramètre movieGenre. S'il n'est pas vide, le code
filtre encore la requête des films afin de se limiter aux films sélectionnés au genre spécifié.
If Not String.IsNullOrEmpty(movieGenre) Then
movies = movies.Where(Function(m) m.Genre.Equals(movieGenre))
End If

Comme indiqué précédemment, la requête n'est pas exécutée sur la base de données jusqu'à
ce que la liste de film est demandée (ce qui arrive dans la vue, après l’activation de la méthode d'action
Index).

Ajoutant la balise à la vue Index pour supporter la recherche par Genre


Ajouter le helper Html.DropDownList dans le fichier Views\Movies\Index.vbhtml, juste avant
le helper TextBox. Le code complet est illustré ci-dessous :
@ModelType IEnumerable(Of MvcMovie.Models.Movie)
@Code
ViewData("Title") = "Index"
End Code

<h2>Index</h2>

<p>
@Html.ActionLink("Create New", "Create")

@Using Html.BeginForm("Index", "Movies", FormMethod.Get)


@<p>Genre: @Html.DropDownList("movieGenre", "All")
Title: @Html.TextBox("SearchString") <br />
<input type="submit" value="Filter" />
</p>
End Using
</p>

<table class="table">
Dans le code suivant :

Genre: @Html.DropDownList("movieGenre", "All")

Le paramètre « movieGenre » fournit un paramètre au helper DropDownList afin de trouver


un IEnumerable<SelectListItem> dans le ViewBag. Le ViewBag a été rempli dans la méthode d'action
:
Function Index(ByVal movieGenre As String, ByVal searchString As String)
Dim genreList As New List(Of String)
Dim genreQuery = From m In db.Movies
Order By m.Genre
Select m.Genre

genreList.AddRange(genreQuery.Distinct)

ViewBag.movieGenre = New SelectList(genreList)


Dim movies = From m In db.Movies
Select m

If Not String.IsNullOrEmpty(searchString) Then


movies = movies.Where(Function(m) m.Title.Contains(searchString))
End If

If Not String.IsNullOrEmpty(movieGenre) Then


movies = movies.Where(Function(m) m.Genre.Equals(movieGenre))
End If

Return View(movies)
End Function

Le paramètre « All » fournit les éléments dans la liste pour être présélectionné. Si nous avions
utilisé le code suivant :
@Html.DropDownList("movieGenre", "Action")
Et nous avons eu un film avec le genre « Action » dans notre base de données, « Action »
pourrait être présélectionnée dans la liste déroulante. Parce que nous n'avons pas un genre de film «
All », il n'y aura aucuns « All » dans la liste SelectList, alors quand nous affichons un retour sans faire
de sélection, la valeur de la chaine de requête de movieGenre est vide.
Exécutez l'application et naviguez jusqu'à /Movies/Index. Essayez une recherche par genre du
film, par le nom du film et les deux critères à la fois.
Ajoutez un nouveau champ
Dans cette section, vous utiliserez Entity Framework Code First Migrations pour migrer certains
changements dans les classes du modèle afin que la modification est appliquée à la base de données.
Par défaut, lorsque vous utilisez Entity Framework Code First pour créer automatiquement une
base de données, comme vous l'avez fait plus tôt dans ce tutoriel, Code First ajoute une table à la base
de données afin de vérifier si le schéma de la base de données est synchronisé avec les classes de
modèle, qu'il a été généré à partir. Si elles ne sont pas synchronisées, Entity Framework génère une
erreur. Cela rend plus facile de traquer les problèmes au moment du développement que vous pourriez
autrement seulement trouver (par Erreurs obscures) au moment de l'exécution.

Mise en place les premières Migrations Code pour modéliser les changements
Accédez à l'Explorateur de solutions. Faites un clic droit sur le fichier Movies.mdf et
sélectionnez supprimer pour supprimer la base de données de films. Si vous ne voyez pas le fichier
Movies.mdf, cliquez sur l'icône Afficher tous les fichiers ci-dessous dans le contour rouge.

Générez l'application pour s'assurer qu'il n'y a pas d'erreurs.


Dans le menu Outils, cliquez sur Gestionnaire de Package NuGet, puis sur Console du
gestionnaire de Package.
Dans la fenêtre de la Console du gestionnaire de Package à la PM> invite entrer
Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDbContext

La commande Enable-Migrations (illustrée ci-dessus) crée un fichier Configuration.vb dans un


nouveau dossier de Migrations.

Visual Studio ouvre le fichier Configuration.vb. Remplacez la méthode Seed dans le fichier
Configuration.vb avec le code suivant :
Protected Overrides Sub Seed(context As MovieDbContext)
context.Movies.AddOrUpdate(Function(i) i.Title,
New Movie() With {
.Title = "When Harry Met Sally",
.ReleaseDate = Date.Parse("1989-1-11"),
.Genre = "Romantic Comedy",
.Price = 7.99D
}, New Movie() With {
.Title = "Ghostbusters ",
.ReleaseDate = Date.Parse("1984-3-13"),
.Genre = "Comedy",
.Price = 8.99D
}, New Movie() With {
.Title = "Ghostbusters 2",
.ReleaseDate = Date.Parse("1986-2-23"),
.Genre = "Comedy",
.Price = 9.99D
}, New Movie() With {
.Title = "Rio Bravo",
.ReleaseDate = Date.Parse("1959-4-15"),
.Genre = "Western",
.Price = 3.99D
})
End Sub

Faites un clic droit sur le trait rouge sinueux sous Movie et sélectionnez l’icône de la lampe,
puis cliquez sur Imports MvcMovie.Models ;

Cela ajoute ce qui suit à l'aide de la déclaration :

Imports MvcMovie.Models

Les Migrations code First appelle la méthode de Seed après chaque migration (c'est-à-dire
appelant la mise à jour de base de données dans la Console du gestionnaire de Package) et cette
méthode met à jour les lignes qui ont déjà été insérés ou insère si elles n'existent pas encore.
La méthode AddOrUpdate dans le code suivant effectue une opération de "upsert" :
context.Movies.AddOrUpdate(Function(i) i.Title,
New Movie() With {
.Title = "When Harry Met Sally",
.ReleaseDate = DateTime.Parse("1989-1-11"),
.Genre = "Romantic Comedy",
.Price = 7.99D
}
Parce que la méthode Seed s'exécute avec chaque migration, vous ne pouvez pas juste
d'insérer les données, parce que les lignes que vous voulez ajouter sera déjà là après la première
migration qui a créé la base de données. L'opération "upsert" évite les erreurs qui se passerait si vous
essayez d'insérer une ligne qui existe déjà, mais elle écrase tout changement des données que vous
pouvez faire pendant que vous testez l'application. Avec les données de test dans certaines tables,
dans certains cas lorsque vous modifiez des données lors du test vous souhaitez que vos modifications
persistent après les mises à jour de base de données. Dans ce cas, vous voulez faire une opération
d'insertion conditionnelle : insérer une ligne uniquement s’il n'existe pas déjà.
Le premier paramètre à passer à la méthode AddOrUpdate, spécifie la propriété à utiliser pour
vérifier si une ligne existe déjà. Pour les données de test que vous avez fourni, la propriété Title peut
servir à cet effet puisque chaque titre dans la liste est unique :

context.Movies.AddOrUpdate(Function(i) i.Title,
Ce code suppose que les titres soient uniques. Si vous ajoutez manuellement un titre en
double, vous obtiendrez l'exception suivante la prochaine fois que vous effectuez une migration.
Sequence contains more than one element
Appuyez sur CTRL-MAJ-B pour générer le projet. (Les étapes suivantes échouera si vous ne
générer pas à ce stade).
L'étape suivante consiste à créer une classe DbMigration pour la migration initiale. Cette
migration crée une nouvelle base de données, c'est pourquoi vous avez supprimé le fichier movie.mdf
dans une étape précédente.
Dans la fenêtre de la Console du gestionnaire de Package, entrez la commande add-migration
Initial pour créer la migration initiale. Le nom « Initial » est arbitraire et est utilisé pour nommer le
fichier de migration créé.

Les Migrations code First crée une autre classe dans le dossier des Migrations (avec le nom
{DateStamp}_Initial.vb, et cette classe contient du code qui crée le schéma de base de données. Le
nom de fichier de migration est préalablement fixé avec un horodatage pour aider à la commande.
Examiner la {DateStamp}_Initial.vb fichier, il contient les instructions pour créer la table Movies pour
la base de données Movies. Lorsque vous mettez à jour la base de données dans les directives qui
suivent, le fichier {DateStamp}_Initial.vb s’exécute et crée le schéma. Puis la méthode Seed s'exécutera
pour remplir la BD avec les données de test.
Dans la Console du gestionnaire de Package, entrez la commande update-database pour créer
la base de données et exécuter la méthode Seed.

Si vous obtenez une erreur indiquant qu’une table existe déjà et elle ne peut pas être créée,
c'est probablement parce que vous avez exécuté l'application une fois que vous avez supprimé la base
de données et avant que vous exécutiez update-database. Dans ce cas, supprimez le fichier
Movies.mdf à nouveau et réessayez la commande update-database. Si vous obtenez toujours une
erreur, supprimez le dossier migrations et son contenu puis commencez par les instructions en haut
de cette page (supprimer le fichier Movies.mdf, puis passez à Enable-Migrations).
Exécutez l'application et accédez à l'URL /Movies. Les données de la méthode Seed sont
affichées.
Ajout d'une propriété de notation pour le modèle de film
Commencez par ajouter une nouvelle propriété Rating à la classe existante Movie. Ouvrez le
fichier Models\Movie.vb et ajouter la propriété Rating comme celui-ci :
Public Property Rating As String
Le code complet de la classe Movie ressemble maintenant au code suivant :
Public Class Movie
Public Property ID As Integer
Public Property Title As String
<Display(Name:="Release Date")>
<DataType(DataType.Date)>
<DisplayFormat(DataFormatString:="{0:yyyy-MM-dd}",
ApplyFormatInEditMode:=True)>
Public Property ReleaseDate As DateTime
Public Property Genre As String
Public Property Price As Decimal
Public Property Rating As String
End Class
Générez l'application (Ctrl + Maj + B).
Parce que vous avez ajouté un nouveau champ à la classe Movie, vous devez également mettre
à jour le Bind afin que cette nouvelle propriété sera incluse. Mettre à jour l'attribut Bind pour les
méthodes d'action Create et Edit en incluant la propriété Rating :
<Bind(Include:="ID,Title,ReleaseDate,Genre,Price,Rating")>
Vous devez également mettre à jour les Templates de vue afin d'afficher, de créer et de
modifier la nouvelle propriété Rating dans l'affichage du navigateur.
Ouvrez le fichier \Views\Movies\Index.vbhtml et ajouter un en-tête de colonne
<th>Rating</th> juste après la colonne Price. Ajoutez ensuite une colonne <td> près de l'extrémité de
la Template pour restituer la valeur @item.Rating. Voici à quoi devrez ressemble la Template de mis
à jour de Index.vbhtml:
@ModelType IEnumerable(Of MvcMovie.Models.Movie)
@Code
ViewData("Title") = "Index"
End Code

<h2>Index</h2>

<p>
@Html.ActionLink("Create New", "Create")
@Using Html.BeginForm("Index", "Movies", FormMethod.Get)
@<p>Genre: @Html.DropDownList("movieGenre", "All")
Title: @Html.TextBox("SearchString") <br />
<input type="submit" value="Filter" /></p>
End Using
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(Function(model) model.Title)
</th>
<th>
@Html.DisplayNameFor(Function(model) model.ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(Function(model) model.Genre)
</th>
<th>
@Html.DisplayNameFor(Function(model) model.Price)
</th>
<th>
@Html.DisplayNameFor(Function(model) model.Rating)
</th>
<th></th>
</tr>

@For Each item In Model


@<tr>
<td>
@Html.DisplayFor(Function(modelItem) item.Title)
</td>
<td>
@Html.DisplayFor(Function(modelItem) item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(Function(modelItem) item.Genre)
</td>
<td>
@Html.DisplayFor(Function(modelItem) item.Price)
</td>
<td>
@Html.DisplayFor(Function(modelItem) item.Rating)
</td>
<td>
@Html.ActionLink("Edit", "Edit", New With {.id = item.ID }) |
@Html.ActionLink("Details", "Details", New With {.id =
item.ID }) |
@Html.ActionLink("Delete", "Delete", New With {.id = item.ID
})
</td>
</tr>
Next

</table>
Ensuite, ouvrez le fichier \Views\Movies\Create.vbhtml et ajoutez le champ Rating en ajoutant
le balisage suivant de met en évidence. Cela rend une zone de texte afin que vous pouvez spécifier un
classement lorsqu'un nouveau film est créé.
<div class="form-group">
@Html.LabelFor(Function(model) model.Price, New With { .class
= "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(Function(model) model.Price)
@Html.ValidationMessageFor(Function(model) model.Price)
</div>
</div>

<div class="form-group">
@Html.LabelFor(Function(model) model.Rating, New With
{.class = "control-label col-md-2"})
<div class="col-md-10">
@Html.EditorFor(Function(model) model.Rating)
@Html.ValidationMessageFor(Function(model) model.Rating)
</div>
</div>

<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-
default" />
</div>
</div>
Vous avez maintenant mis à jour le code de l'application pour prendre en charge la nouvelle
propriété Rating.
Exécutez l'application et accédez à l'URL /Movies. Lorsque vous procédez ainsi, cependant,
vous verrez une des erreurs suivantes :
Le modèle permettant la sauvegarde du contexte « MovieDBContext » a été modifié depuis la
création de la base de données. Utiliser les Migrations Code First pour mettre à jour la base de données
(http://go.microsoft.com/fwlink/?LinkId=238269).

Vous voyez cette erreur parce que la classe de modèle Movie mis à jour dans l'application est
maintenant différente de celui du schéma de la table Movie de la base de données existante. (Il n'y a
pas Rating de colonne dans la table de base de données.)
Il y a quelques approches pour résoudre l'erreur :
1. Autoriser l’Entity Framework automatiquement de supprimer et recréer la base de données basée
avec le nouveau schéma de classe de modèle. Cette approche est très pratique au début du cycle
de développement lorsque vous faites un développement actif sur une base de données de test ;
il vous permet de faire évoluer rapidement l’ensemble du schéma de la base de données et du
modèle. L'inconvénient, cependant, est que vous perdez les données existantes dans la base de
données —vous ne voulez pas utiliser cette approche sur une base de données de production !
2. Modifier explicitement le schéma de la base de données existante pour qu'elle corresponde aux
classes du modèle. L'avantage de cette approche est que vous conservez vos données. Vous
pouvez effectuer cette modification soit manuellement ou par la création d’un script de
changement de la base de données.
3. Utiliser Les Migrations Code First afin de mettre à jour le schéma de la base de données.
Pour ce tutoriel, nous allons utiliser les Migrations Code First.
Mettre à jour la méthode de Seed afin qu'il fournisse une valeur pour la nouvelle colonne.
Ouvrir le fichier Migrations\Configuration.vb et ajoutez le champ Rating à chaque objet.
New Movie() With {
.Title = "When Harry Met Sally",
.ReleaseDate = Date.Parse("1989-1-11"),
.Genre = "Romantic Comedy",
.Price = 7.99D,
.Rating = "PG"
}
Générez la solution, puis ouvrez la fenêtre de la Console du gestionnaire de Package et entrez
la commande suivante :
add-migration Rating
La commande add-migration indique au Framework de la migration d'examiner le modèle
actuel Movie en le comparant avec le schéma de BD Movies actuel et de créer le code nécessaire pour
effectuer la migration de la BD selon le nouveau modèle. Le nom Rating est arbitraire et est utilisé
pour nommer le fichier de migration. Il est utile d'utiliser un nom significatif pour chaque étape de la
migration.
Lorsque cette commande se termine, Visual Studio ouvre le fichier de classe qui définit la
nouvelle classe dérivée de la DbMigration en redéfinissant la méthode Up, vous pouvez voir le code
qui crée la nouvelle colonne.
Public Partial Class Rating
Inherits DbMigration

Public Overrides Sub Up()


AddColumn("dbo.Movies", "Rating", Function(c) c.String())
End Sub

Public Overrides Sub Down()


DropColumn("dbo.Movies", "Rating")
End Sub
End Class

Générez la solution et puis entrez la commande update-database dans la fenêtre de la Console


du gestionnaire de Package.
L'image suivante montre la sortie dans la fenêtre de Console du gestionnaire de Package (le
cachet de date, ajout de note sera différent).

Relancez l'application et accédez à l'URL /Movies. Vous pouvez voir le nouveau champ Rating.

Cliquez sur le lien Create New pour ajouter un nouveau film. Notez que vous pouvez ajouter
une note.
Cliquez sur créer. Le nouveau film, dont la valeur nominale, apparait désormais dans la liste
des films :

Maintenant que le projet utilise les migrations, vous n'aurez pas besoin de supprimer la base
de données lorsque vous ajoutez un nouveau champ ou autrement mettre à jour le schéma. Vous
devez également ajouter le champ Rating pour les vues Edit, Detail et Delete.
Vous pouvez entrer la commande « update-database » dans la fenêtre de la Console du
gestionnaire de paquet à nouveau et aucun code de migration ne serait exécuté, car le schéma
correspond au modèle. Cependant, l’exécution de « update-database » exécutera la méthode Seed à
nouveau, et si vous avez modifié les données de Seed, les modifications seront perdues parce que la
de méthode Seed met à jours ou insert les données.
Dans cette section, vous avez vu comment vous pouvez modifier les objets de modèle et de
maintenir la base de données en synchronisation avec les modifications. Vous avez appris aussi un
moyen de remplir une base de données nouvellement créée avec des données d’exemple, alors vous
pouvez essayer plusieurs scénarios. C'était juste une introduction rapide au premier Code.
Ajout de la validation
Dans cette section, vous allez ajouter une logique de validation pour la classe Movie et vous
allez obliger en sorte que les règles de validation sont appliquées à chaque fois qu'un utilisateur tente
de créer ou éditer un film à l'aide de l'application.

Garder les choses propres


Parmi les principes de conception de base de ASP.NET MVC est le développement propre ("ne
pas répéter vous-même"). ASP.NET MVC vous invite à spécifier les fonctionnalités ou le comportement
qu'une seule fois et puis l'ai figuré partout dans une application. Cela réduit la quantité de code, que
vous devez écrire et rend le code que vous écrivez correcte avec moins erreur possible et plus facile à
entretenir.
Le support de validation fourni par ASP.NET MVC et Entity Framework Code First est un
excellent exemple de ce principe. Vous pouvez spécifier de façon déclarative des règles de validation
en un seul endroit (dans la classe de modèle) et les règles sont appliquées partout dans l'application.
Voyons comment vous pouvez tirer parti de cette prise en charge de la validation dans cette
application.

Ajout de règles de Validation du modèle de film


Vous commencerez par ajout d'une logique de validation à la classe de Movie.
Ouvrez le fichier Movie.vb. Noter que l'espace de noms
System.ComponentModel.DataAnnotations ne contient pas de System.Web. DataAnnotations fournit
un ensemble intégré d'attributs de validation que vous pouvez appliquer de façon déclarative à une
classe ou une propriété. (Il contient également les attributs de mise en forme comme type de données
qui aident à la mise en forme et ne fournissent aucune validation).
Maintenant mettre à jour la classe Movie pour profiter de l'intégration des Required,
StringLength, RegularExpression et attributs de validation de Range. Remplacez la classe Movie par
le texte suivant :
Public Class Movie
Public Property ID As Integer

<StringLength(60, MinimumLength:=3)>
Public Property Title As String

<Display(Name:="Release Date")>
<DataType(DataType.Date)>
<DisplayFormat(DataFormatString:="{0:yyyy-MM-dd}",
ApplyFormatInEditMode:=True)>
Public Property ReleaseDate As DateTime

<RegularExpression("^[A-Z]+[a-zA-Z''-'\s]*$")>
<Required>
<StringLength(30)>
Public Property Genre As String

<Range(1, 100)>
<DataType(DataType.Currency)>
Public Property Price As Decimal

<RegularExpression("^[A-Z]+[a-zA-Z''-'\s]*$")>
<StringLength(5)>
Public Property Rating As String
End Class
L'attribut StringLength définit la longueur maximale de la chaine et il décrit cette limitation sur
la base de données, donc le schéma de base de données va changer. Faites un clic droit sur la table de
Movies dans l'Explorateur de serveurs, puis cliquez sur Ouvrir la définition de Table :

Dans l'image ci-dessus, vous pouvez voir tous les champs de chaine sont sur NVARCHAR (MAX).
Nous utiliserons les migrations pour mettre à jour le schéma. Générez la solution, puis ouvrez la
fenêtre de la Console du gestionnaire de Package et entrez les commandes suivantes :
add-migration DataAnnotations
update-database
Lorsque cette commande se termine, Visual Studio ouvre le fichier de classe qui définit la
nouvelle classe dérivée de DbMigration avec le nom spécifié (DataAnnotations) et dans la méthode
Up, vous pouvez voir le code qui met à jour les contraintes du schéma :
Public Overrides Sub Up()
AlterColumn("dbo.Movies", "Title", Function(c) c.String(maxLength := 60))
AlterColumn("dbo.Movies", "Genre", Function(c) c.String(nullable := False,
maxLength := 30))
AlterColumn("dbo.Movies", "Rating", Function(c) c.String(maxLength := 5))
End Sub

Le champ Genre est n’est plus nullable (autrement dit, vous devez entrer une valeur). Le champ
Rating a une longueur maximale de 5 et le champ Title a une longueur maximale de 60. La longueur
minimale du champ Title est de 3 et la gamme de Price n'ont pas créé des modifications de schéma.
Examiner le schéma Movies :
Les champs de Data Type montrent les nouvelles limites de longueur et de Genre n'autorise
plus la valeur nullable.
Les attributs de validation spécifient le comportement que vous souhaitez appliquer sur les
propriétés de modèle sont appliqués également. Les attributs Required et MinimumLength indique
qu'une propriété doit avoir une valeur ; mais rien n'empêche un utilisateur d'entrer des espaces blancs
pour satisfaire cette validation. L'attribut RegularExpression sert à limiter ce que les caractères
peuvent être entrées. Dans le code ci-dessus, Genre et Rating doivent utiliser uniquement des lettres
(l'espace blanc, chiffres et caractères spéciaux ne sont pas autorisés). L'attribut Range contraint la
valeur dans une plage spécifiée. L'attribut StringLength vous permet de définir la longueur maximale
d'une propriété de type chaine de caractères et éventuellement sa longueur minimale. Les valeurs des
types (tels que decimal, int, float, DateTime) sont fondamentalement nécessaires et n'avez pas besoin
de l’attribut Required.
Code First vérifie tout d'abord que les règles de validation, que vous spécifiez dans une classe
de modèle sont appliquées avant que l'application enregistre les modifications dans la base de
données. Par exemple, le code suivant lève une exception DbEntityValidationException lorsque la
méthode SaveChanges() est appelée, car plusieurs valeurs obligatoires sont manquants:
Dim db = New MovieDbContext()
Dim movie = New Movie()
movie.Title = "Gone with the Wind"
db.Movies.Add(movie)
db.SaveChanges() ' <= Will throw server side validation exception
Le code ci-dessus lève l'exception suivante :
Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
Avoir des règles de validation appliquées automatiquement par le Framework .NET contribue
à rendre votre application plus robuste. Il s'assure également que vous n’oubliez pas de valider quelque
chose et de laisser par mégarde des données incorrectes dans la base de données.

Erreur de validation de l'interface utilisateur dans ASP.NET MVC


Exécutez l'application et accédez à l'URL /Movies.
Cliquez sur le lien Create New pour ajouter un nouveau film. Remplissez le formulaire avec des
valeurs non valides. Dès la validation du côté client jQuery détecte l'erreur, il affiche un message
d'erreur.
Noter qu’à l’aide de la validation de jQuery pour les paramètres régionaux non anglais qui
utilisent une virgule («, ») pour une virgule décimale, vous devez inclure le NuGet globaliser comme
décrit plus haut.
Remarquez comment la forme a utilisé automatiquement une couleur de bordure rouge pour
mettre en évidence les zones de texte qui contiennent des données incorrectes et a émis un message
d'erreur de validation appropriée en regard de chacun d'eux. Les erreurs sont appliquées à la fois (à
l'aide de JavaScript et de jQuery) côté client et côté serveur (dans le cas où un utilisateur a JavaScript
désactivé).
Un réel avantage est que vous n'a pas besoin de changer une seule ligne de code dans la classe
MoviesController ou dans la vue de Create.vbhtml afin de permettre à cette validation UI. Le
contrôleur et les vues que vous avez créées plus tôt ramassé automatiquement les règles de validation
que vous avez spécifié à l'aide d'attributs de validation sur les propriétés de la classe de modèle Movie.
Test de validation à l'aide de la méthode d'action Edit et vérifier que la même validation est appliquée.
Les données du formulaire ne sont pas envoyées au serveur, jusqu'à ce qu'il n'y a aucune erreur
de validation du côté client. Vous pouvez vérifier cela en mettant un point d'arrêt dans la méthode
HTTP Post, en utilisant l'outil fiddler, ou IE outils développeur F12.

Comment la Validation se produit dans la méthode d'Action et la vue Create


Vous vous demandez peut-être comment la validation UI a été générée sans mises à jour du
code dans le contrôleur ou la vue. La liste suivante montre ce à quoi ressemblent les méthodes Create
de la classe MovieController. Elles ne sont pas changées depuis que vous les avez créé au début.
' GET: Movies/Create
Function Create() As ActionResult
Return View()
End Function

' POST: Movies/Create


'Afin de déjouer les attaques par sur-validation, activez les propriétés
spécifiques que vous voulez lier. Pour
'plus de détails, voir http://go.microsoft.com/fwlink/?LinkId=317598.
<HttpPost()>
<ValidateAntiForgeryToken()>
Function Create(<Bind(Include:="ID,Title,ReleaseDate,Genre,Price,Rating")>
ByVal movie As Movie) As ActionResult
If ModelState.IsValid Then
db.Movies.Add(movie)
db.SaveChanges()
Return RedirectToAction("Index")
End If
Return View(movie)
End Function

La première méthode d'action Create (HTTP GET) affiche le formulaire initial de créer. La
deuxième version ([HttpPost]) gère le post de formulaire. La deuxième méthode Create (la version
HttpPost) appelle ModelState.IsValid pour vérifier si le film a des erreurs de validation. Appeler cette
méthode évalue tous les attributs de validation qui ont été appliqués à l'objet. Si l'objet comporte des
erreurs de validation, la méthode Create réaffiche le formulaire. S'il n'y a pas d'erreurs, la méthode
enregistre le nouveau film dans la base de données. Dans notre exemple de film, la forme n'est pas
publiée sur le serveur que lorsqu'il n’y a plus des erreurs de validation détectées côté client ; la seconde
méthode Create n'est jamais appelée. Si vous désactivez JavaScript dans votre navigateur, la validation
du client est désactivée et la méthode Create (HTTP POST) appelle ModelState.IsValid pour vérifier si
le film a des erreurs de validation.
Vous pouvez définir un point d'arrêt dans la méthode Create (HttpPost) et vérifier que la
méthode n'est jamais appelée, la validation côté client ne soumettra pas les données de formulaire
lorsque des erreurs de validation sont détectées. Si vous désactivez JavaScript dans votre navigateur,
puis envoyez le formulaire avec des erreurs, le point d'arrêt sera activé. Vous obtenez toujours une
validation complète sans JavaScript. L'image suivante montre comment désactiver JavaScript dans
Internet Explorer.
L'image suivante montre comment désactiver JavaScript dans le navigateur FireFox.

L'image suivante montre comment désactiver JavaScript dans le navigateur de Chrome.

Voici le modèle de vue de Create.vbhtml qui vous structure plus tôt dans le tutoriel. Il est utilisé
par les méthodes d'action ci-dessus tous les deux pour afficher le formulaire initial et réaffichez en cas
d'erreur.
@ModelType MvcMovie.Models.Movie
@Code
ViewData("Title") = "Create"
End Code

<h2>Create</h2>

@Using (Html.BeginForm())
@Html.AntiForgeryToken()

@<div class="form-horizontal">
<h4>Movie</h4>
<hr />
@Html.ValidationSummary(true)
<div class="form-group">
@Html.LabelFor(Function(model) model.Title, New With { .class
= "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(Function(model) model.Title)
@Html.ValidationMessageFor(Function(model) model.Title)
</div>
</div>

@* Other fields removed for brevity *@

<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-
default" />
</div>
</div>
</div>
End Using

<div>
@Html.ActionLink("Back to List", "Index")
</div>

@Section Scripts
@Scripts.Render("~/bundles/jqueryval")
End Section
Remarquez comment le code utilise un helper Html.EditorFor à la sortie de l'élément <input>
pour chaque propriété d’un film. À côté de chaque helper, il y a un appel au Helper
Html.ValidationMessageFor. Ces deux méthodes (helper) fonctionnent avec un objet du modèle qui
est passé par le contrôleur à la vue (dans ce cas précis, un objet de Movie). Ils recherchent
automatiquement les attributs de validation spécifiés dans le modèle et affiche les messages d'erreur
appropries.
Ce qui est vraiment sympa dans cette approche, c'est que ni le contrôleur ni la Template de
vue Create sait quoi que ce soit concernant les règles de validation réellement appliquées ou les
messages d'erreur spécifiques affichées. Les règles de validation et les chaines d'erreur sont spécifiées
uniquement dans la classe Movie. Ces mêmes règles de validations sont automatiquement appliquées
à la vue Edit et tous les autres Template de vues que vous pouvez créer pour modifier votre modèle.
Si vous souhaitez modifier la logique de validation par la suite, vous pouvez le faire en une
seule place en ajoutant des attributs de validation du modèle (dans cet exemple, la classe Movie). Vous
n'aurez pas à vous soucier des différentes parties de l’application étant incompatible avec la façon
dont les règles sont appliquées — toute la logique de validation est définie dans un seul endroit et
utilisée partout. Cela maintient le code très propre et le rend facile à entretenir et à évoluer. Et cela
signifie que vous serez pleinement honorant les bons principes de développement.

Utilisation des attributs DataType


Ouvrez le fichier Movie.vb et examinez la classe Movie. L'espace de noms
System.ComponentModel.DataAnnotations fournit des attributs de mise en forme en plus de
l'ensemble intégré des attributs de validation. Nous avons déjà appliqué une valeur d'énumération
DataType aux champs ReleaseDate et Price. Le code suivant affiche l'attribut DataType approprié des
propriétés avec ReleaseDate et Price.
<DataType(DataType.Date)>
Public Property ReleaseDate As DateTime

<DataType(DataType.Currency)>
Public Property Price As Decimal
Les attributs DataType fournissent uniquement des indices pour le moteur de vue pour mettre
en forme les données (et fournir des attributs tels que <a> pour les URL et <a
href="mailto:EmailAddress.com"> pour le courrier électronique. Vous pouvez utiliser l'attribut
RegularExpression pour valider le format des données. L'attribut DataType est utilisé pour spécifier le
type de données qui est plus spécifique que le type intrinsèque de la base de données, ce ne sont pas
des attributs de validation. Dans ce cas, nous voulons seulement garder une trace de la date, pas la
date et l'heure. L'énumération DataType prévoit de nombreux types de données, telles que Date,
heure, numéro de téléphone, monnaie, EmailAddress et bien plus encore. L'attribut DataType peut
également permettre à l'application de fournir automatiquement les fonctionnalités spécifiques à un
type. Par exemple, un lien mailto: peut être créé pour DataType.EmailAddress, et un sélecteur de date
peut être fourni pour DataType.Date dans les navigateurs qui prennent en charge HTML5. Les attributs
DataType émet les attributs de données de HTML 5 - (prononcé data dash) que les navigateurs HTML
5 peuvent comprendre. Les attributs DataType ne fournissent pas toute validation.
DataType.Date ne précise pas le format de la date qui s'affiche. Par défaut, le champ de
données est affiché selon les formats par défaut basés sur du serveur CultureInfo.
L'attribut DisplayFormat sert à spécifier explicitement le format de date :
<DisplayFormat(DataFormatString:="{0:yyyy-MM-dd}",
ApplyFormatInEditMode:=True)>
Public Property ReleaseDate As DateTime
Le paramètre ApplyFormatInEditMode spécifie que la mise en forme spécifiée doit également
s'appliquer lorsque la valeur est affichée dans une zone de texte pour l'édition. (Vous ne voulez pas
que pour certains domaines — par exemple, pour les valeurs monétaires, vous ne voulez pas afficher
le symbole monétaire dans la zone de texte pour le modifier.)
Vous pouvez utiliser l'attribut DisplayFormat seulement, mais c'est généralement une bonne
idée d'utiliser l'attribut DataType également. L'attribut DataType transmet la sémantique des données
plutôt que comment il restituer sur un écran et offre les avantages suivants que vous n'obtenez pas
avec DisplayFormat :
 Le navigateur peut activer des fonctionnalités de HTML5 (par exemple pour afficher un
contrôle de type calendar, le symbole monétaire locale appropriée, liens de courriel, etc..).
 Par défaut, le navigateur renvoie les données au format correct basé sur vos paramètres
régionaux.
 L'attribut DataType peut activer MVC pour choisir le Template de champ approprié pour
afficher les données (les DisplayFormat si utilisé seul utilise le Template de chaine de
caractère).
Si vous utilisez l'attribut de DataType avec un champ de type date, vous devez spécifier
l'attribut DisplayFormat également afin de s'assurer que le champ s'affiche correctement dans les
navigateurs Chrome.
Remarque : le validation jQuery ne fonctionne pas avec l'attribut Range et DateTime. Par
exemple, le code suivant affichera toujours une erreur de validation du côté client, même lorsque la
date est dans la plage spécifiée :
<Range(GetType(DateTime), "1/1/1966", "1/1/2020")>
Public Property ReleaseDate As DateTime
Vous devrez désactiver la validation de date de jQuery pour utiliser l'attribut Range avec
DateTime. Il n'est généralement pas une bonne pratique de compiler les dates en durs dans vos
modèles, l'utilisation de l'attribut Range et DateTime est déconseillée.
Le code suivant illustre la combinaison des attributs sur une seule ligne :
<Display(Name:="Release Date"), DataType(DataType.Date)>
Public Property ReleaseDate As DateTime

<RegularExpression("^[A-Z]+[a-zA-Z''-'\s]*$"), Required,
StringLength(30)>
Public Property Genre As String

<Range(1, 100), DataType(DataType.Currency)>


Public Property Price As Decimal

<RegularExpression("^[A-Z]+[a-zA-Z''-'\s]*$"), StringLength(5)>
Public Property Rating As String

Examinant et les méthodes Details et Delete


Dans cette partie, vous allez examiner les méthodes de Details et Delete générés
automatiquement.
Ouvrir le contrôleur MovieController.vb et d'examiner la méthode Details.

' GET: Movies/Details/5


Function Details(ByVal id As Integer?) As ActionResult
If IsNothing(id) Then
Return New HttpStatusCodeResult(HttpStatusCode.BadRequest)
End If
Dim movie As Movie = db.Movies.Find(id)
If IsNothing(movie) Then
Return HttpNotFound()
End If
Return View(movie)
End Function

Le moteur de génération de modèles automatique MVC qui a créé cette méthode d'action
ajoute un commentaire indiquant une requête HTTP qui appelle la méthode. Dans ce cas, c'est une
requête GET avec trois segments d'URL, le contrôleur Movies, la méthode d’action Details et une
valeur ID.
Code First facilite tout d'abord la rechercher des données à l'aide de la méthode Find. Un
élément de sécurité important construit dans la méthode, c'est que le code vérifie que la méthode
Find a trouvé un film avant le code n’essaie de faire quelque chose avec elle. Par exemple, un pirate
pourrait introduire des erreurs dans le site en changeant l'URL créée par les liens de
http://localhost:xxxx/films/détails/1 vers quelque chose comme
http://localhost:xxxx/films/détails/12345 (ou une autre valeur qui ne représente pas un film réel). Si
vous n'avez pas vérifié que le film est null, un film null se traduirait par une erreur de base de données.
Examinez les méthodes Delete et DeleteConfirmed .
' GET: Movies/Delete/5
Function Delete(ByVal id As Integer?) As ActionResult
If IsNothing(id) Then
Return New HttpStatusCodeResult(HttpStatusCode.BadRequest)
End If
Dim movie As Movie = db.Movies.Find(id)
If IsNothing(movie) Then
Return HttpNotFound()
End If
Return View(movie)
End Function

' POST: Movies/Delete/5


<HttpPost()>
<ActionName("Delete")>
<ValidateAntiForgeryToken()>
Function DeleteConfirmed(ByVal id As Integer) As ActionResult
Dim movie As Movie = db.Movies.Find(id)
db.Movies.Remove(movie)
db.SaveChanges()
Return RedirectToAction("Index")
End Function

Notez que la méthode Delete (HTTP Get) ne supprime pas le film spécifié, elle retourne une
vue du film où vous pouvez le soumettre en une requête (HttpPost) pour la suppression... Effectuer
une opération de suppression en réponse à une requête HttpGet (ou d'ailleurs, effectuer une
opération de modification, une opération de création, ou toute autre opération qui modifie des
données) ouvre une brèche de sécurité.
La méthode HttpPost qui supprime les données est nommée DeleteConfirmed pour donner à
la méthode HTTP POST, une signature unique ou un nom. Les signatures des deux méthodes sont
indiquées ci-dessous :
// GET: /Movies/Delete/5
public ActionResult Delete(int? id)

//
// POST: /Movies/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
Le common language runtime (CLR) nécessite d'avoir une signature de paramètre unique afin
de surcharger les méthodes (même nom de méthode mais la liste des paramètres différente).
Cependant, ici, vous avez besoin de deux méthodes Delete--un pour GET--et un POST, et que les deux
ont la même signature de paramètre. (Ils ont tous les deux en besoin d'accepter un seul entier comme
paramètre).
Pour résoudre ce point, vous pouvez faire une ou deux choses. On doit donner les méthodes
des noms différents. C'est ce que le mécanisme de génération de modèles automatique fait dans
l'exemple précédent. Cependant, cela revient à introduire un petit problème : ASP.NET mappe les
segments d'URL à des méthodes d'action par leur nom, et si vous renommez une méthode, le routage
normalement ne serait pas en mesure de trouver cette méthode. La solution est ce que vous voyez
dans l'exemple, qui consiste à ajouter l'attribut ActionName("Delete") pour la méthode
DeleteConfirmed. Cela réalise efficacement le mappage pour le système de routage afin une requête
POST qui inclut dans son URL /Delete/ peut être traitée par la méthode DeleteConfirmed .
Une autre manière commune pour éviter un problème avec des méthodes qui ont des
signatures et des noms identiques est de modifier artificiellement la signature de la méthode POST en
incluant un paramètre inutilisé. Par exemple, certains développeurs ajoutent un paramètre type
FormCollection qui est passé à la méthode POST et puis tout simplement n'utilisez pas ce paramètre :
Function DeleteConfirmed(ByVal notUsed As FormCollection, ByVal id As
Integer) As ActionResult
Dim movie As Movie = db.Movies.Find(id)
If movie Is Nothing Then Return HttpNotFound()
db.Movies.Remove(movie)
db.SaveChanges()
Return RedirectToAction("Index")
End Function
Résumé
Vous avez maintenant une application ASP.NET MVC complète qui stocke les données dans
une base de données locale. Vous pouvez créer, lire, mettre à jour, supprimer et Rechercher des films.