Partager via


Examen des méthodes de modification et de la vue de modification (VB)

par Rick Anderson

Ce tutoriel vous apprend les principes de base de la création d’une application web MVC ASP.NET à l’aide de Microsoft Visual Web Developer 2010 Express Service Pack 1, qui est une version gratuite de Microsoft Visual Studio. Avant de commencer, vérifiez que vous avez installé les conditions préalables répertoriées ci-dessous. Vous pouvez les installer en cliquant sur le lien suivant : Web Platform Installer. Vous pouvez également installer individuellement les prérequis à l’aide des liens suivants :

Si vous utilisez Visual Studio 2010 au lieu de Visual Web Developer 2010, installez les prérequis en cliquant sur le lien suivant : Conditions préalables pour Visual Studio 2010.

Un projet Visual Web Developer avec VB.NET code source est disponible pour accompagner cette rubrique. Téléchargez la version VB.NET. Si vous préférez C#, basculez vers la version C# de ce didacticiel.

Dans cette section, vous allez examiner les méthodes et vues d’action générées pour le contrôleur de film. Ensuite, vous allez ajouter une page de recherche personnalisée.

Exécutez l’application et accédez au Movies contrôleur en ajoutant /Movies à l’URL dans la barre d’adresse de votre navigateur. Maintenez le pointeur de la souris sur un lien Modifier pour afficher l’URL vers laquelle il est lié.

Capture d’écran montrant l’application de déplacement MVC avec le lien Modifier pour l’un des films sélectionnés.

Le lien Edit a été généré par la Html.ActionLink méthode dans la vue Views\Movies\Index.vbhtml :

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

Capture d’écran montrant html.ActionLink dans un éditeur de code.

L’objet Html est un assistance exposé à l’aide d’une propriété sur la WebViewPage classe de base. La ActionLink méthode de l’assistance facilite la génération dynamique de liens hypertexte HTML qui relient les méthodes d’action sur les contrôleurs. Le premier argument de la ActionLink méthode est le texte du lien à afficher (par exemple). <a>Edit Me</a> Le deuxième argument est le nom de la méthode d’action à appeler. L’argument final est un objet anonyme qui génère les données de routage (dans ce cas, l’ID de 4).

Le lien généré affiché dans l’image précédente est http://localhost:xxxxx/Movies/Edit/4. L’itinéraire par défaut prend le modèle {controller}/{action}/{id}d’URL . Par conséquent, ASP.NET se traduit http://localhost:xxxxx/Movies/Edit/4 en une requête en méthode Edit d’action du Movies contrôleur avec le paramètre ID égal à 4.

Vous pouvez également passer des paramètres de méthode d’action à l’aide d’une chaîne de requête. Par exemple, l’URL http://localhost:xxxxx/Movies/Edit?ID=4 transmet également le paramètre ID 4 à la Edit méthode d’action du Movies contrôleur.

EditQueryString

Ouvrez le Movies contrôleur. Les deux Edit méthodes d’action sont indiquées ci-dessous.

'
' GET: /Movies/Edit/5

Function Edit(id As Integer) As ViewResult
    Dim movie As Movie = db.Movies.Find(id)
    Return View(movie)
End Function

'
' POST: /Movies/Edit/5

<HttpPost()>
Function Edit(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

Notez que la deuxième méthode d’action Edit est précédée de l’attribut HttpPost. Cet attribut spécifie que la surcharge de la Edit méthode peut être appelée uniquement pour les requêtes POST. Vous pouvez appliquer l’attribut HttpGet à la première méthode d’édition, mais cela n’est pas nécessaire, car il s’agit de la valeur par défaut. (Nous allons faire référence à des méthodes d’action qui sont implicitement affectées à l’attribut HttpGet en tant que HttpGet méthodes.)

La HttpGet Edit méthode prend le paramètre ID de film, recherche le film à l’aide de la méthode Entity Framework Find et retourne le film sélectionné en mode Édition. Quand le système de génération de modèles automatique a créé la vue Edit, il a examiné la classe Movie et a créé le code pour restituer les éléments <label> et <input> de chaque propriété de la classe. L’exemple suivant montre l’affichage Modifier qui a été généré :

@ModelType MvcMovie.Movie

@Code
    ViewData("Title") = "Edit"
End Code

<h2>Edit</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@Using Html.BeginForm()
    @Html.ValidationSummary(True)
    @<fieldset>
        <legend>Movie</legend>

        @Html.HiddenFor(Function(model) model.ID)

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.Title)
            @Html.ValidationMessageFor(Function(model) model.Title)
        </div>

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.ReleaseDate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.ReleaseDate)
            @Html.ValidationMessageFor(Function(model) model.ReleaseDate)
        </div>

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.Genre)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.Genre)
            @Html.ValidationMessageFor(Function(model) model.Genre)
        </div>

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.Price)
            @Html.ValidationMessageFor(Function(model) model.Price)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
End Using

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

Notez que le modèle d’affichage a une @ModelType MvcMovie.Models.Movie instruction en haut du fichier . Cela spécifie que la vue s’attend à ce que le modèle de vue soit de type Movie.

Le code généré automatiquement utilise plusieurs méthodes d’assistance pour simplifier le balisage HTML. L’assistance Html.LabelFor affiche le nom du champ (« Title », « ReleaseDate », « Genre » ou « Price »). L’assistance Html.EditorFor affiche un élément HTML <input> . L’assistance Html.ValidationMessageFor affiche les 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 la source de la page. Le code HTML de la page ressemble à l’exemple suivant. (Le balisage du menu a été exclu pour plus de clarté.)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Edit</title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.5.1.min.js" type="text/javascript"></script>
    <script src="/Scripts/modernizr-1.7.min.js" type="text/javascript"></script>
</head>
<body>
    <div class="page">
        <header>
            <div id="title">
                <h1>MVC Movie App</h1>
            </div>
           ...
        </header>
        <section id="main">

<h2>Edit</h2>

<script src="/Scripts/jquery.validate.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>

<form action="/Movies/Edit/4" method="post">    <fieldset>
        <legend>Movie</legend>

        <input data-val="true" data-val-number="The field ID must be a number." 
    data-val-required="The ID field is required." id="ID" name="ID" type="hidden" value="4" />

        <div class="editor-label">
            <label for="Title">Title</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" id="Title" name="Title" type="text" value="Rio Bravo" />
            <span class="field-validation-valid" data-valmsg-for="Title" data-valmsg-replace="true"></span>
        </div>

        <div class="editor-label">
            <label for="ReleaseDate">ReleaseDate</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" data-val="true" data-val-required="The ReleaseDate field is required." 
    id="ReleaseDate" name="ReleaseDate" type="text" value="4/15/1959 12:00:00 AM" />
            <span class="field-validation-valid" data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span>
        </div>

        <div class="editor-label">
            <label for="Genre">Genre</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" id="Genre" name="Genre" type="text" value="Western" />
            <span class="field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
        </div>

        <div class="editor-label">
            <label for="Price">Price</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" data-val="true" data-val-number="The field Price must be a number." 
    data-val-required="The Price field is required." id="Price" name="Price" type="text" value="9.99" />
            <span class="field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
</form>
<div>
    <a href="/Movies">Back to List</a>
</div>

        </section>
        <footer>
        </footer>
    </div>
</body>
</html>

Les <input> éléments se trouvent dans un élément HTML <form> dont action l’attribut est défini pour publier sur l’URL /Movies/Edit . Les données de formulaire sont publiées sur le serveur lorsque le bouton Modifier est cliqué.

Traitement de la requête POST

Le code suivant montre la version HttpPost de la méthode d’action Edit.

'
' POST: /Movies/Edit/5

<HttpPost()>
Function Edit(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

Le classeur de modèles d’infrastructure ASP.NET prend les valeurs de formulaire publiées et crée un Movie objet passé en tant que movie paramètre. La ModelState.IsValid vérification du code vérifie que les données soumises dans le formulaire peuvent être utilisées pour modifier un Movie objet. Si les données sont valides, le code enregistre les données de film dans la Movies collection de l’instance MovieDBContext . Le code enregistre ensuite les nouvelles données vidéo dans la base de données en appelant la SaveChanges méthode de MovieDBContext, qui conserve les modifications apportées à la base de données. Après avoir enregistré les données, le code redirige l’utilisateur vers la Index méthode d’action de la MoviesController classe, ce qui entraîne l’affichage du film mis à jour dans la liste des films.

Si les valeurs publiées ne sont pas valides, elles sont réaffichées dans le formulaire. Les Html.ValidationMessageFor helpers du modèle de vue Edit.vbhtml s’occupent de l’affichage des messages d’erreur appropriés.

abcNotValid

Remarque sur les paramètres régionaux Si vous travaillez normalement avec des paramètres régionaux autres que l’anglais, consultez Prise en charge ASP.NET validation MVC 3 avec des paramètres régionaux non anglais.

Rendre la méthode Edit plus robuste

La HttpGet Edit méthode générée par le système de génération automatique ne vérifie pas que l’ID passé à celui-ci est valide. Si un utilisateur supprime le segment d’ID de l’URL (http://localhost:xxxxx/Movies/Edit), l’erreur suivante s’affiche :

Null_ID

Un utilisateur peut également transmettre un ID qui n’existe pas dans la base de données, par http://localhost:xxxxx/Movies/Edit/1234exemple . Vous pouvez apporter deux modifications à la méthode d’action HttpGet Edit pour résoudre cette limitation. Tout d’abord, modifiez le ID paramètre pour avoir la valeur par défaut zéro lorsqu’un ID n’est pas transmis explicitement. Vous pouvez également vérifier que la Find méthode a réellement trouvé un film avant de renvoyer l’objet film au modèle d’affichage. La méthode mise à jour Edit est indiquée ci-dessous.

Public Function Edit(Optional ByVal id As Integer = 0) As ActionResult
    Dim movie As Movie = db.Movies.Find(id)
    If movie Is Nothing Then
        Return HttpNotFound()
    End If
    Return View(movie)
End Function

Si aucun film n’est trouvé, la HttpNotFound méthode est appelée.

Toutes les HttpGet méthodes suivent un modèle similaire. Ils obtiennent un objet vidéo (ou liste d’objets, dans le cas de Index), et passent le modèle à la vue. La Create méthode transmet un objet vidéo vide à l’affichage Create. Toutes les méthodes qui créent, modifient, suppriment ou changent d’une quelconque manière des données le font dans la surcharge HttpPost de la méthode. La modification de données dans une méthode HTTP GET est un risque de sécurité. La modification de données dans une méthode GET enfreint également les meilleures pratiques HTTP et le modèle REST architectural, qui spécifie que les requêtes GET ne doivent pas changer l’état de votre application. En d’autres termes, l’exécution d’une opération GET doit être une opération sécurisée qui n’a aucun effet secondaire.

Ajout d’une méthode de recherche et d’une vue de recherche

Dans cette section, vous allez ajouter une méthode d’action SearchIndex qui vous permet de rechercher des films par genre ou par nom. Cette opération sera disponible à l’aide de l’URL /Movies/SearchIndex . La demande affiche un formulaire HTML qui contient des éléments d’entrée qu’un utilisateur peut remplir pour rechercher un film. Lorsqu’un utilisateur envoie le formulaire, la méthode d’action obtient les valeurs de recherche publiées par l’utilisateur et utilise les valeurs pour rechercher la base de données.

SearchIndx_SM

Affichage du formulaire SearchIndex

Commencez par ajouter une méthode d’action SearchIndex à la classe existante MoviesController . La méthode retourne une vue qui contient un formulaire HTML. Voici le code :

Public Function SearchIndex(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(s) s.Title.Contains(searchString)) 
    End If
    Return View(movies) 
End Function

La première ligne de la SearchIndex méthode 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 le magasin de données.

Si le searchString paramètre contient une chaîne, la requête films est modifiée pour filtrer la valeur de la chaîne de recherche à l’aide du code suivant :

If Not String.IsNullOrEmpty(searchString) Then
films = films. Where(Function(s) s.Title.Contains(searchString))
End If

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 réellement itérée ou que la ToList méthode soit appelée. Dans l’exemple SearchIndex , la requête est exécutée dans la vue SearchIndex. Pour plus d’informations sur l’exécution différée des requêtes, consultez Exécution de requête.

Vous pouvez maintenant implémenter l’affichage SearchIndex qui affichera le formulaire à l’utilisateur. Cliquez avec le bouton droit dans la SearchIndex méthode, puis cliquez sur Ajouter un affichage. Dans la boîte de dialogue Ajouter un affichage , spécifiez que vous allez passer un Movie objet au modèle d’affichage en tant que classe de modèle. Dans la liste des modèles de structure Scaffold , choisissez Liste, puis cliquez sur Ajouter.

AddSearchView

Lorsque vous cliquez sur le bouton Ajouter , le modèle de vue Views\Movies\SearchIndex.vbhtml est créé. Étant donné que vous avez sélectionné Liste dans la liste des modèles de structure , Visual Web Developer a généré automatiquement (généré automatiquement) du contenu par défaut dans l’affichage. La structure a créé un formulaire HTML. Il a examiné la classe et créé du Movie code pour afficher <label> les éléments pour chaque propriété de la classe. La liste ci-dessous montre la vue Créer qui a été générée :

@ModelType IEnumerable(Of MvcMovie.Movie)

@Code
    ViewData("Title") = "SearchIndex"
End Code

<h2>SearchIndex</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th>
            Title
        </th>
        <th>
            ReleaseDate
        </th>
        <th>
            Genre
        </th>
        <th>
            Price
        </th>
        <th></th>
    </tr>

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

</table>

Exécutez l’application et accédez à /Movies/SearchIndex. Ajoutez une chaîne de requête comme ?searchString=ghost à l’URL. Les films filtrés sont affichés.

SearchQryStr

Si vous modifiez la signature de la SearchIndex méthode pour avoir un paramètre nommé id, le id paramètre correspond à l’espace {id} réservé pour les itinéraires par défaut définis dans le fichier Global.asax .

{controller}/{action}/{id}

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

Public Function SearchIndex(ByVal id As String) As ActionResult
Dim searchString As String = id
Dim movies = From m In db.Movies
             Select m

If Not String.IsNullOrEmpty(searchString) Then
    movies = movies.Where(Function(s) s.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 routage (un segment de l’URL) et non pas en tant que valeur de chaîne de requête.

SearchRouteData

Cependant, vous ne pouvez pas attendre des utilisateurs qu’ils modifient l’URL à chaque fois qu’ils veulent rechercher un film. Vous allez donc ajouter l’interface utilisateur pour les aider à filtrer les films. Si vous avez modifié la signature de la SearchIndex méthode pour tester comment passer le paramètre ID lié à l’itinéraire, remplacez-le afin que votre SearchIndex méthode accepte un paramètre de chaîne nommé searchString:

Ouvrez le fichier Views\Movies\SearchIndex.vbhtml , puis juste après @Html.ActionLink("Create New", "Create"), ajoutez ce qui suit :

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

L’assistance Html.BeginForm crée une balise d’ouverture <form> . L’assistance Html.BeginForm entraîne la publication du formulaire lorsque l’utilisateur envoie le formulaire en cliquant sur le bouton Filtrer .

Exécutez l’application et essayez de rechercher un film.

SearchIndxIE9_title

Il n’y a pas HttpPost de surcharge de la SearchIndex méthode. Vous n’en avez pas besoin, car la méthode ne change pas l’état de l’application, en filtrant simplement les données. Si vous avez ajouté la méthode suivante HttpPost SearchIndex, l’appelant d’action correspond à la SearchIndex HttpPost méthode et la HttpPost SearchIndex méthode s’exécuterait comme indiqué dans l’image ci-dessous.

<HttpPost()>
 Public Function SearchIndex(ByVal fc As FormCollection, ByVal searchString As String) As String
     Return "<h3> From [HttpPost]SearchIndex: " & searchString & "</h3>"
 End Function

SearchPostGhost

Ajout de la recherche par genre

Si vous avez ajouté la HttpPost version de la méthode, supprimez-la SearchIndex maintenant.

Ensuite, vous allez ajouter une fonctionnalité pour permettre aux utilisateurs de rechercher des films par genre. Remplacez la méthode SearchIndex par le code suivant :

Public Function SearchIndex(ByVal movieGenre As String, ByVal searchString As String) As ActionResult
    Dim GenreLst = New List(Of String)()

    Dim GenreQry = From d In db.Movies
                   Order By d.Genre
                   Select d.Genre
    GenreLst.AddRange(GenreQry.Distinct())
    ViewBag.movieGenre = New SelectList(GenreLst)

    Dim movies = From m In db.Movies
                 Select m

    If Not String.IsNullOrEmpty(searchString) Then
        movies = movies.Where(Function(s) s.Title.Contains(searchString))
    End If

    If String.IsNullOrEmpty(movieGenre) Then
        Return View(movies)
    Else
        Return View(movies.Where(Function(x) x.Genre = movieGenre))
    End If

End Function

Cette version de la SearchIndex méthode prend un paramètre supplémentaire, à savoir movieGenre. Les premières lignes de code créent un List objet pour contenir des genres vidéo à partir de la base de données.

Le code suivant est une requête LINQ qui récupère tous les genres dans la base de données.

Dim GenreQry = From d In db.Movies
                   Order By d.Genre
                   Select d.Genre

Le code utilise la AddRange méthode de la collection générique List pour ajouter tous les genres distincts à la liste. (Sans le modificateur, les Distinct genres en double seraient ajoutés , par exemple, la comédie serait ajoutée deux fois dans notre exemple). Le code stocke ensuite la liste des genres dans l’objet ViewBag .

Le code suivant montre comment vérifier le movieGenre paramètre. S’il n’est pas vide, le code limite davantage la requête films pour limiter les films sélectionnés au genre spécifié.

If String.IsNullOrEmpty(movieGenre) Then
        Return View(movies)
    Else
        Return View(movies.Where(Function(x) x.Genre = movieGenre))
    End If

Ajout de balisage à la vue SearchIndex pour prendre en charge la recherche par genre

Ajoutez un Html.DropDownList assistance au fichier Views\Movies\SearchIndex.vbhtml , juste avant l’assistance TextBox . Le balisage terminé est illustré ci-dessous :

<p>
    @Html.ActionLink("Create New", "Create")
    @Code
    ViewData("Title") = "SearchIndex"
    Using (Html.BeginForm())
         @<p> Genre: @Html.DropDownList("movieGenre", "All")
         Title: @Html.TextBox("SearchString") 
         <input type="submit" value="Filter" /></p>
        End Using
End Code
</p>

Exécutez l’application et accédez à /Movies/SearchIndex. Essayez une recherche par genre, par nom de film, et par les deux critères.

Dans cette section, vous avez examiné les méthodes d’action CRUD et les vues générées par l’infrastructure. Vous avez créé une méthode d’action de recherche et une vue qui permettent aux utilisateurs de rechercher par titre et genre de film. Dans la section suivante, vous allez découvrir comment ajouter une propriété au Movie modèle et comment ajouter un initialiseur qui créera automatiquement une base de données de test.