Partager via


Fournir une prise en charge des entrées dans les formulaires de données CRUD (créer, lire, mettre à jour, supprimer)

par Microsoft

Télécharger le PDF

Il s’agit de l’étape 5 d’un didacticiel gratuit sur l’application « NerdDinner » qui explique comment créer une application web petite mais complète à l’aide de ASP.NET MVC 1.

L’étape 5 montre comment aller plus loin dans notre classe DinnersController en activant également la prise en charge de la modification, de la création et de la suppression de dîners.

Si vous utilisez ASP.NET MVC 3, nous vous recommandons de suivre les didacticiels Prise en main Avec MVC 3 ou MVC Music Store.

Étape 5 de NerdDinner : créer, mettre à jour, supprimer des scénarios de formulaire

Nous avons introduit des contrôleurs et des vues, et expliqué comment les utiliser pour implémenter une expérience de référencement/détails pour les dîners sur site. Notre prochaine étape sera d’aller plus loin dans notre classe DinnersController et d’activer la prise en charge de la modification, de la création et de la suppression des dîners avec celle-ci.

URL gérées par DinnersController

Nous avons précédemment ajouté des méthodes d’action à DinnersController qui ont implémenté la prise en charge de deux URL : /Dinners et /Dinners/Details/[id].

URL VERBE Objectif
/Dîners/ GET Affichez la liste HTML des prochains dîners.
/Dinners/Details/[id] GET Afficher les détails d’un dîner spécifique.

Nous allons maintenant ajouter des méthodes d’action pour implémenter trois URL supplémentaires : /Dinners/Edit/[id], /Dinners/Create et /Dinners/Delete/[id]. Ces URL permettent de prendre en charge la modification des dîners existants, la création de nouveaux dîners et la suppression des dîners.

Nous allons prendre en charge les interactions de verbe HTTP GET et HTTP POST avec ces nouvelles URL. Les requêtes HTTP GET adressées à ces URL affichent l’affichage HTML initial des données (un formulaire rempli avec les données Dinner dans le cas de « edit », un formulaire vide dans le cas de « create » et un écran de confirmation de suppression dans le cas de « delete »). Les requêtes HTTP POST adressées à ces URL enregistrent/mettent à jour/suppriment les données Dinner dans notre site DinnerRepository (et à partir de là vers la base de données).

URL VERBE Objectif
/Dinners/Edit/[id] GET Affichez un formulaire HTML modifiable rempli avec des données Dinner.
POST Enregistrez les modifications de formulaire pour un Dîner particulier dans la base de données.
/Dinners/Create GET Affichez un formulaire HTML vide qui permet aux utilisateurs de définir de nouveaux dîners.
POST Créez un dîner et enregistrez-le dans la base de données.
/Dinners/Delete/[id] GET Afficher l’écran de confirmation de suppression.
POST Supprime le dîner spécifié de la base de données.

Modifier la prise en charge

Commençons par implémenter le scénario « modifier ».

Méthode d’action d’édition HTTP-GET

Nous allons commencer par implémenter le comportement HTTP « GET » de notre méthode d’action de modification. Cette méthode est appelée lorsque l’URL /Dinners/Edit/[id] est demandée. Notre implémentation se présente comme suit :

//
// GET: /Dinners/Edit/2

public ActionResult Edit(int id) {

    Dinner dinner = dinnerRepository.GetDinner(id);
    
    return View(dinner);
}

Le code ci-dessus utilise DinnerRepository pour récupérer un objet Dinner. Il restitue ensuite un modèle View à l’aide de l’objet Dinner. Étant donné que nous n’avons pas transmis explicitement de nom de modèle à la méthode d’assistance View(), elle utilise le chemin d’accès par défaut basé sur la convention pour résoudre le modèle d’affichage : /Views/Dinners/Edit.aspx.

Nous allons maintenant créer ce modèle d’affichage. Pour ce faire, cliquez avec le bouton droit dans la méthode Edit et sélectionnez la commande de menu contextuel « Ajouter une vue » :

Capture d’écran de la création d’un modèle d’affichage pour ajouter une vue dans Visual Studio.

Dans la boîte de dialogue « Ajouter une vue », nous allons indiquer que nous transmettons un objet Dinner à notre modèle d’affichage en tant que modèle, et que nous choisissons de créer automatiquement un modèle « Modifier » :

Capture d’écran de l’ajout d’un affichage pour créer automatiquement une structure d’un modèle d’édition.

Lorsque nous cliquons sur le bouton « Ajouter », Visual Studio ajoute un nouveau fichier de modèle d’affichage « Edit.aspx » pour nous dans le répertoire « \Views\Dinners ». Il ouvre également le nouveau modèle d’affichage « Edit.aspx » dans l’éditeur de code, rempli avec une implémentation initiale de la structure « Modifier », comme ci-dessous :

Capture d’écran du nouveau modèle d’affichage Modifier dans l’éditeur de code.

Nous allons apporter quelques modifications à la structure « modifier » par défaut générée, et mettons à jour le modèle d’affichage de modification pour avoir le contenu ci-dessous (ce qui supprime quelques-unes des propriétés que nous ne voulons pas exposer) :

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Edit: <%=Html.Encode(Model.Title)%>
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Edit Dinner</h2>

    <%=Html.ValidationSummary("Please correct the errors and try again.") %>  
    
    <% using (Html.BeginForm()) { %>

        <fieldset>
            <p>
                <label for="Title">Dinner Title:</label>
                <%=Html.TextBox("Title") %>
                <%=Html.ValidationMessage("Title", "*") %>
            </p>
            <p>
                <label for="EventDate">EventDate:</label>
                <%=Html.TextBox("EventDate", String.Format("{0:g}", Model.EventDate))%>
                <%=Html.ValidationMessage("EventDate", "*") %>
            </p>
            <p>
                <label for="Description">Description:</label>
                <%=Html.TextArea("Description") %>
                <%=Html.ValidationMessage("Description", "*")%>
            </p>
            <p>
                <label for="Address">Address:</label>
                <%=Html.TextBox("Address") %>
                <%=Html.ValidationMessage("Address", "*") %>
            </p>
            <p>
                <label for="Country">Country:</label>
                <%=Html.TextBox("Country") %>               
                <%=Html.ValidationMessage("Country", "*") %>
            </p>
            <p>
                <label for="ContactPhone">ContactPhone #:</label>
                <%=Html.TextBox("ContactPhone") %>
                <%=Html.ValidationMessage("ContactPhone", "*") %>
            </p>
            <p>
                <label for="Latitude">Latitude:</label>
                <%=Html.TextBox("Latitude") %>
                <%=Html.ValidationMessage("Latitude", "*") %>
            </p>
            <p>
                <label for="Longitude">Longitude:</label>
                <%=Html.TextBox("Longitude") %>
                <%=Html.ValidationMessage("Longitude", "*") %>
            </p>
            <p>
                <input type="submit" value="Save"/>
            </p>
        </fieldset>
        
    <% } %>
    
</asp:Content>

Lorsque nous exécutons l’application et demandons l’URL « /Dinners/Edit/1 », la page suivante s’affiche :

Capture d’écran de la page Mon application M V C.

Le balisage HTML généré par notre vue ressemble à ce qui suit. Il s’agit d’un code HTML standard, avec un <élément de formulaire> qui effectue une requête HTTP POST vers l’URL /Dinners/Edit/1 lorsque le bouton d’entrée « Enregistrer » <type="submit"/> est envoyé. Un élément d’entrée HTML <type="text"/> a été généré pour chaque propriété modifiable :

Capture d’écran du balisage H T M L généré.

Méthodes Html.BeginForm() et Html.TextBox() Html Helper

Notre modèle de vue « Edit.aspx » utilise plusieurs méthodes « Html Helper » : Html.ValidationSummary(), Html.BeginForm(), Html.TextBox() et Html.ValidationMessage(). En plus de générer du balisage HTML pour nous, ces méthodes d’assistance fournissent une prise en charge intégrée de la gestion et de la validation des erreurs.

Méthode d’assistance Html.BeginForm()

La méthode d’assistance Html.BeginForm() est la sortie de l’élément de formulaire> HTML <dans notre balisage. Dans notre modèle d’affichage Edit.aspx, vous remarquerez que nous appliquons une instruction C# « using » lors de l’utilisation de cette méthode. L’accolade ouverte indique le début du contenu du <formulaire> , et l’accolade fermante est ce qui indique la fin de l’élément </form> :

<% using (Html.BeginForm()) { %>

   <fieldset>
   
      <!-- Fields Omitted for Brevity -->
   
      <p>
         <input type="submit" value="Save"/>
      </p>
   </fieldset>
   
<% } %>

Si vous trouvez l’approche de l’instruction « using » non naturelle pour un scénario comme celui-ci, vous pouvez utiliser une combinaison Html.BeginForm() et Html.EndForm() (qui fait la même chose) :

<% Html.BeginForm();  %>

   <fieldset>
   
      <!-- Fields Omitted for Brevity -->
   
      <p>
          <input type="submit" value="Save"/>
      </p>
   </fieldset>
   
<% Html.EndForm(); %>

L’appel de Html.BeginForm() sans aucun paramètre entraîne la sortie d’un élément de formulaire qui effectue un HTTP-POST vers l’URL de la requête actuelle. C’est pourquoi notre vue Modifier génère un <élément form action="/Dinners/Edit/1 » method="post ».> Nous aurions également pu passer des paramètres explicites à Html.BeginForm() si nous voulions publier dans une autre URL.

Méthode d’assistance Html.TextBox()

Notre vue Edit.aspx utilise la méthode d’assistance Html.TextBox() pour générer <les éléments input type="text"/> :

<%= Html.TextBox("Title") %>

La méthode Html.TextBox() ci-dessus prend un seul paramètre qui est utilisé pour spécifier à la fois les attributs id/name de l’élément <input type="text"/> à sortir, ainsi que la propriété de modèle à partir de laquelle remplir la valeur de la zone de texte. Par exemple, l’objet Dinner que nous avons passé à la vue Edit avait une valeur de propriété « Title » de .NET Futures », et par conséquent, notre méthode Html.TextBox(« Title ») a appelé la sortie : <input id="Title » name="Title » type="text » value= ».NET Futures » />.

Vous pouvez également utiliser le premier paramètre Html.TextBox() pour spécifier l’id/nom de l’élément, puis transmettre explicitement la valeur à utiliser comme deuxième paramètre :

<%= Html.TextBox("Title", Model.Title)%>

Souvent, nous voulons effectuer une mise en forme personnalisée sur la valeur qui est sortie. La méthode statique String.Format() intégrée à .NET est utile pour ces scénarios. Notre modèle de vue Edit.aspx utilise ceci pour mettre en forme la valeur EventDate (qui est de type DateTime) afin qu’elle n’affiche pas de secondes pour l’heure :

<%= Html.TextBox("EventDate", String.Format("{0:g}", Model.EventDate)) %>

Un troisième paramètre de Html.TextBox() peut éventuellement être utilisé pour générer des attributs HTML supplémentaires. L’extrait de code ci-dessous montre comment restituer un attribut size="30 » supplémentaire et un attribut class="mycssclass » sur l’élément <input type="text"/> . Notez comment nous échappons le nom de l’attribut de classe à l’aide d’un caractère « @ », car « class » est un mot clé réservé en C#:

<%= Html.TextBox("Title", Model.Title, new { size=30, @class="myclass" } )%>

Implémentation de la méthode d’action d’édition HTTP-POST

Nous avons maintenant implémenté la version HTTP-GET de notre méthode d’action Modifier. Lorsqu’un utilisateur demande l’URL /Dinners/Edit/1, il reçoit une page HTML comme suit :

Capture d’écran de la sortie H T M L lorsque l’utilisateur demande un dîner d’édition.

En appuyant sur le bouton « Enregistrer », une publication de formulaire est envoyée à l’URL /Dinners/Edit/1 et envoie les valeurs du formulaire d’entrée> HTML <à l’aide du verbe HTTP POST. Implémentons maintenant le comportement HTTP POST de notre méthode d’action de modification, qui gère l’enregistrement du Dîner.

Nous allons commencer par ajouter une méthode d’action « Modifier » surchargée à notre DinnersController avec un attribut « AcceptVerbs » qui indique qu’elle gère les scénarios HTTP POST :

//
// POST: /Dinners/Edit/2

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
   ...
}

Lorsque l’attribut [AcceptVerbs] est appliqué aux méthodes d’action surchargées, ASP.NET MVC gère automatiquement la répartition des demandes vers la méthode d’action appropriée en fonction du verbe HTTP entrant. Les requêtes HTTP POST adressées à /Dinners/Edit/[id] sont envoyées à la méthode Edit ci-dessus, tandis que toutes les autres requêtes de verbe HTTP adressées aux URL /Dinners/Edit/[id] vont à la première méthode Edit que nous avons implémentée (qui n’avait pas d’attribut [AcceptVerbs] ).

Rubrique secondaire : Pourquoi différencier via des verbes HTTP ?
Vous pouvez vous demander pourquoi utilisons-nous une URL unique et différenciant son comportement via le verbe HTTP ? Pourquoi ne pas simplement avoir deux URL distinctes pour gérer le chargement et l’enregistrement des modifications de modification ? Par exemple : /Dinners/Edit/[id] pour afficher le formulaire initial et /Dinners/Save/[id] pour gérer la publication de formulaire pour l’enregistrer ? L’inconvénient de la publication de deux URL distinctes est que dans les cas où nous publions dans /Dinners/Save/2, puis que nous devons réafficher le formulaire HTML en raison d’une erreur d’entrée, l’utilisateur final aura l’URL /Dinners/Save/2 dans la barre d’adresse de son navigateur (car il s’agissait de l’URL sur laquelle le formulaire a publié). Si l’utilisateur final signe cette page réaffichée dans la liste des favoris de son navigateur, ou copie/colle l’URL et l’envoie par courrier électronique à un ami, il finit par enregistrer une URL qui ne fonctionnera plus à l’avenir (car cette URL dépend des valeurs de publication). En exposant une URL unique (par exemple: /Dinners/Edit/[id]) et en différenciant le traitement de celle-ci par un verbe HTTP, il est sûr pour les utilisateurs finaux de mettre en signet la page de modification et/ou d’envoyer l’URL à d’autres personnes.

Récupération des valeurs de publication de formulaire

Il existe différentes façons d’accéder aux paramètres de formulaire publiés dans notre méthode HTTP POST « Edit ». Une approche simple consiste simplement à utiliser la propriété Request sur la classe de base controller pour accéder à la collection de formulaires et récupérer directement les valeurs publiées :

//
// POST: /Dinners/Edit/2

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {

    // Retrieve existing dinner
    Dinner dinner = dinnerRepository.GetDinner(id);

    // Update dinner with form posted values
    dinner.Title = Request.Form["Title"];
    dinner.Description = Request.Form["Description"];
    dinner.EventDate = DateTime.Parse(Request.Form["EventDate"]);
    dinner.Address = Request.Form["Address"];
    dinner.Country = Request.Form["Country"];
    dinner.ContactPhone = Request.Form["ContactPhone"];

    // Persist changes back to database
    dinnerRepository.Save();

    // Perform HTTP redirect to details page for the saved Dinner
    return RedirectToAction("Details", new { id = dinner.DinnerID });
}

L’approche ci-dessus est toutefois un peu détaillée, en particulier une fois que nous avons ajouté la logique de gestion des erreurs.

Une meilleure approche pour ce scénario consiste à tirer parti de la méthode d’assistance UpdateModel() intégrée sur la classe de base du contrôleur. Il prend en charge la mise à jour des propriétés d’un objet que nous transmettons à l’aide des paramètres de formulaire entrants. Il utilise la réflexion pour déterminer les noms de propriétés sur l’objet, puis les convertit et leur affecte automatiquement des valeurs en fonction des valeurs d’entrée envoyées par le client.

Nous pourrions utiliser la méthode UpdateModel() pour simplifier notre action d’édition HTTP-POST à l’aide de ce code :

//
// POST: /Dinners/Edit/2

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    UpdateModel(dinner);

    dinnerRepository.Save();

    return RedirectToAction("Details", new { id = dinner.DinnerID });
}

Nous pouvons maintenant visiter l’URL /Dinners/Edit/1 et modifier le titre de notre dîner :

Capture d’écran de la page Modifier le dîner.

Lorsque nous cliquons sur le bouton « Enregistrer », nous effectuons une publication de formulaire dans notre action Modifier, et les valeurs mises à jour sont conservées dans la base de données. Nous sommes ensuite redirigés vers l’URL de détails du dîner (qui affiche les valeurs nouvellement enregistrées) :

Capture d’écran de l’URL des détails du dîner.

Gestion des erreurs de modification

Notre implémentation HTTP-POST actuelle fonctionne correctement, sauf en cas d’erreurs.

Lorsqu’un utilisateur fait une erreur lors de la modification d’un formulaire, nous devons nous assurer que le formulaire est réaffiché avec un message d’erreur d’information qui le guide pour le corriger. Cela inclut les cas où un utilisateur final publie une entrée incorrecte (par exemple, une chaîne de date incorrecte), ainsi que les cas où le format d’entrée est valide, mais où il existe une violation de règle métier. En cas d’erreurs, le formulaire doit conserver les données d’entrée que l’utilisateur a entrées à l’origine afin qu’il n’ait pas à remplir manuellement ses modifications. Ce processus doit se répéter autant de fois que nécessaire jusqu’à ce que le formulaire se termine correctement.

ASP.NET MVC inclut des fonctionnalités intégrées intéressantes qui facilitent la gestion des erreurs et la redisplay des formulaires. Pour voir ces fonctionnalités en action, nous allons mettre à jour notre méthode d’action Modifier avec le code suivant :

//
// POST: /Dinners/Edit/2

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    try {

        UpdateModel(dinner);

        dinnerRepository.Save();

        return RedirectToAction("Details", new { id=dinner.DinnerID });
    }
    catch {

        foreach (var issue in dinner.GetRuleViolations()) {
            ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
        }

        return View(dinner);
    }
}

Le code ci-dessus est similaire à notre implémentation précédente, sauf que nous encapsulons maintenant un bloc de gestion des erreurs try/catch autour de notre travail. Si une exception se produit lors de l’appel de UpdateModel(), ou lorsque nous essayons d’enregistrer dinnerRepository (ce qui déclenchera une exception si l’objet Dinner que nous essayons d’enregistrer n’est pas valide en raison d’une violation de règle dans notre modèle), notre bloc de gestion des erreurs intercepte s’exécute. Dans celui-ci, nous effectuons une boucle sur les violations de règle qui existent dans l’objet Dinner et les ajoutons à un objet ModelState (que nous aborderons sous peu). Nous redisplayons ensuite la vue.

Pour voir ce fonctionnement, réexécutons l’application, modifiez un dîner et changez-le pour avoir un titre vide, un EventDate de « BOGUS », et utiliser un numéro de téléphone britannique avec une valeur pays/région usa. Lorsque nous appuyons sur le bouton « Enregistrer », notre méthode HTTP POST Edit ne sera pas en mesure d’enregistrer le Dîner (en raison d’erreurs) et réaffichera le formulaire :

Capture d’écran du formulaire redisplay en raison d’erreurs à l’aide de la méthode H T T P S P O S T Edit.

Notre application a une expérience d’erreur décente. Les éléments de texte avec l’entrée non valide sont mis en surbrillance en rouge et les messages d’erreur de validation s’affichent à l’utilisateur final à leur sujet. Le formulaire conserve également les données d’entrée que l’utilisateur a entrées à l’origine, afin qu’il n’ait rien à remplir.

Comment, me demanderiez-vous, cela s’est-il produit ? Comment les zones de texte Title, EventDate et ContactPhone se mettent-elles en rouge et savent-elles générer les valeurs utilisateur entrées à l’origine ? Comment les messages d’erreur ont-ils été affichés dans la liste en haut ? La bonne nouvelle est que cela ne s’est pas produit par magie , mais plutôt parce que nous avons utilisé certaines des fonctionnalités intégrées ASP.NET MVC qui facilitent la validation des entrées et les scénarios de gestion des erreurs.

Présentation de ModelState et des méthodes d’assistance HTML de validation

Les classes de contrôleur ont une collection de propriétés « ModelState » qui permet d’indiquer qu’il existe des erreurs avec un objet de modèle passé à une vue. Les entrées d’erreur de la collection ModelState identifient le nom de la propriété de modèle avec le problème (par exemple , « Title », « EventDate » ou « ContactPhone ») et autorisent la spécification d’un message d’erreur convivial (par exemple , « Title is required »).

La méthode d’assistance UpdateModel() remplit automatiquement la collection ModelState lorsqu’elle rencontre des erreurs lors de la tentative d’affectation de valeurs de formulaire aux propriétés de l’objet de modèle. Par exemple, la propriété EventDate de notre objet Dinner est de type DateTime. Lorsque la méthode UpdateModel() n’a pas pu lui attribuer la valeur de chaîne « BOGUS » dans le scénario ci-dessus, la méthode UpdateModel() a ajouté une entrée à la collection ModelState indiquant qu’une erreur d’affectation s’était produite avec cette propriété.

Les développeurs peuvent également écrire du code pour ajouter explicitement des entrées d’erreur dans la collection ModelState comme nous le faisons ci-dessous dans notre bloc de gestion des erreurs « catch », qui remplit la collection ModelState avec des entrées basées sur les violations de règle actives dans l’objet Dinner :

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    try {
    
        UpdateModel(dinner);

        dinnerRepository.Save();

        return RedirectToAction("Details", new { id=dinner.DinnerID });
    }
    catch {
    
        foreach (var issue in dinner.GetRuleViolations()) {
            ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
        }

        return View(dinner);
    }
}

Intégration de Html Helper à ModelState

Les méthodes d’assistance HTML, telles que Html.TextBox(), case activée la collection ModelState lors du rendu de la sortie. S’il existe une erreur pour l’élément, ils restituent la valeur entrée par l’utilisateur et une classe d’erreur CSS.

Par exemple, dans notre vue « Modifier », nous utilisons la méthode d’assistance Html.TextBox() pour restituer l’EventDate de notre objet Dinner :

<%= Html.TextBox("EventDate", String.Format("{0:g}", Model.EventDate)) %>

Lorsque la vue a été rendue dans le scénario d’erreur, la méthode Html.TextBox() a vérifié la collection ModelState pour voir s’il y avait des erreurs associées à la propriété « EventDate » de notre objet Dinner. Lorsqu’il a déterminé qu’il y avait une erreur, il a rendu l’entrée utilisateur envoyée (« BOGUS ») en tant que valeur, et a ajouté une classe d’erreur css au <balisage input type="textbox"/> qu’elle a généré :

<input class="input-validation-error"id="EventDate" name="EventDate" type="text" value="BOGUS"/>

Vous pouvez personnaliser l’apparence de la classe d’erreur css pour qu’elle ressemble comme vous le souhaitez. La classe d’erreur CSS par défaut , « input-validation-error », est définie dans la feuille de style \content\site.css et se présente comme suit :

.input-validation-error
{
    border: 1px solid #ff0000;
    background-color: #ffeeee;
}

Cette règle CSS est à l’origine de la mise en surbrillance de nos éléments d’entrée non valides, comme ci-dessous :

Capture d’écran des éléments d’entrée non valides mis en surbrillance.

Html.ValidationMessage() Helper, méthode

La méthode d’assistance Html.ValidationMessage() peut être utilisée pour générer le message d’erreur ModelState associé à une propriété de modèle particulière :

<%= Html.ValidationMessage("EventDate")%>

Les sorties de code ci-dessus : <span class="field-validation-error »> La valeur 'BOGUS' n’est pas valide</span>

La méthode d’assistance Html.ValidationMessage() prend également en charge un deuxième paramètre qui permet aux développeurs de remplacer le message texte d’erreur affiché :

<%= Html.ValidationMessage("EventDate","*") %>

Les sorties de code ci-dessus : <span class="field-validation-error">*</span> au lieu du texte d’erreur par défaut lorsqu’une erreur est présente pour la propriété EventDate.

Html.ValidationSummary() Helper, méthode

La méthode d’assistance Html.ValidationSummary() peut être utilisée pour afficher un message d’erreur récapitulative, accompagné d’une <liste ul><li/></ul> de tous les messages d’erreur détaillés de la collection ModelState :

Capture d’écran de la liste de tous les messages d’erreur détaillés dans la collection ModelState.

La méthode d’assistance Html.ValidationSummary() prend un paramètre de chaîne facultatif, qui définit un message d’erreur récapitulative à afficher au-dessus de la liste des erreurs détaillées :

<%= Html.ValidationSummary("Please correct the errors and try again.") %>

Vous pouvez éventuellement utiliser CSS pour remplacer l’apparence de la liste d’erreurs.

Utilisation d’une méthode AddRuleViolations Helper

Notre implémentation http-POST Edit initiale a utilisé une instruction foreach dans son bloc catch pour effectuer une boucle sur les violations de règle de l’objet Dinner et les ajouter à la collection ModelState du contrôleur :

catch {
        foreach (var issue in dinner.GetRuleViolations()) {
            ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
        }

        return View(dinner);
    }

Nous pouvons rendre ce code un peu plus propre en ajoutant une classe « ControllerHelpers » au projet NerdDinner et en implémentant une méthode d’extension « AddRuleViolations » qui ajoute une méthode d’assistance à la classe ASP.NET MVC ModelStateDictionary. Cette méthode d’extension peut encapsuler la logique nécessaire pour remplir modelStateDictionary avec une liste d’erreurs RuleViolation :

public static class ControllerHelpers {

   public static void AddRuleViolations(this ModelStateDictionary modelState, IEnumerable<RuleViolation> errors) {
   
       foreach (RuleViolation issue in errors) {
           modelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
       }
   }
}

Nous pouvons ensuite mettre à jour notre méthode d’action HTTP-POST Edit pour utiliser cette méthode d’extension pour remplir la collection ModelState avec nos violations de règle Dinner.

Terminer les implémentations de méthode d’action d’édition

Le code ci-dessous implémente toute la logique de contrôleur nécessaire pour notre scénario d’édition :

//
// GET: /Dinners/Edit/2

public ActionResult Edit(int id) {

    Dinner dinner = dinnerRepository.GetDinner(id);
    
    return View(dinner);
}

//
// POST: /Dinners/Edit/2

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    try {
    
        UpdateModel(dinner);

        dinnerRepository.Save();

        return RedirectToAction("Details", new { id=dinner.DinnerID });
    }
    catch {
    
        ModelState.AddRuleViolations(dinner.GetRuleViolations());

        return View(dinner);
    }
}

La bonne chose à propos de notre implémentation d’édition est que ni notre classe de contrôleur ni notre modèle Vue ne doivent connaître quoi que ce soit sur la validation spécifique ou les règles métier appliquées par notre modèle Dinner. Nous pouvons ajouter des règles supplémentaires à notre modèle à l’avenir et n’avons pas besoin d’apporter des modifications de code à notre contrôleur ou à notre vue pour qu’elles soient prises en charge. Cela nous offre la flexibilité nécessaire pour faire évoluer facilement nos exigences d’application à l’avenir avec un minimum de modifications de code.

Créer un support

Nous avons terminé l’implémentation du comportement « Modifier » de notre classe DinnersController. Passons maintenant à l’implémentation de la prise en charge « Créer » sur celle-ci, qui permettra aux utilisateurs d’ajouter de nouveaux dîners.

Méthode d’action de création HTTP-GET

Nous allons commencer par implémenter le comportement HTTP « GET » de notre méthode create action. Cette méthode est appelée quand une personne visite l’URL /Dinners/Create . Notre implémentation se présente comme suit :

//
// GET: /Dinners/Create

public ActionResult Create() {

    Dinner dinner = new Dinner() {
        EventDate = DateTime.Now.AddDays(7)
    };

    return View(dinner);
}

Le code ci-dessus crée un objet Dinner et affecte sa propriété EventDate à une semaine ultérieure. Il restitue ensuite une vue basée sur le nouvel objet Dinner. Étant donné que nous n’avons pas explicitement passé de nom à la méthode d’assistance View(), elle utilise le chemin d’accès par défaut basé sur la convention pour résoudre le modèle d’affichage : /Views/Dinners/Create.aspx.

Nous allons maintenant créer ce modèle d’affichage. Pour ce faire, cliquez avec le bouton droit dans la méthode d’action Créer et sélectionnez la commande de menu contextuel « Ajouter une vue ». Dans la boîte de dialogue « Ajouter une vue », nous allons indiquer que nous transmettons un objet Dinner au modèle d’affichage et que nous choisissons de créer automatiquement un modèle « Créer » :

Capture d’écran de l’ajout d’un affichage pour créer un modèle d’affichage.

Lorsque nous cliquons sur le bouton « Ajouter », Visual Studio enregistre une nouvelle vue « Create.aspx » basée sur la structure dans le répertoire « \Views\Dinners » et l’ouvre dans l’IDE :

Capture d’écran de l’ID E pour modifier le code.

Nous allons apporter quelques modifications au fichier de structure par défaut « create » qui a été généré pour nous, et le modifier pour qu’il ressemble à ce qui suit :

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
     Host a Dinner
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Host a Dinner</h2>

    <%=Html.ValidationSummary("Please correct the errors and try again.") %>
 
    <% using (Html.BeginForm()) {%>
  
        <fieldset>
            <p>
                <label for="Title">Title:</label>
                <%= Html.TextBox("Title") %>
                <%= Html.ValidationMessage("Title", "*") %>
            </p>
            <p>
                <label for="EventDate">EventDate:</label>
                <%=Html.TextBox("EventDate") %>
                <%=Html.ValidationMessage("EventDate", "*") %>
            </p>
            <p>
                <label for="Description">Description:</label>
                <%=Html.TextArea("Description") %>
                <%=Html.ValidationMessage("Description", "*") %>
            </p>
            <p>
                <label for="Address">Address:</label>
                <%=Html.TextBox("Address") %>
                <%=Html.ValidationMessage("Address", "*") %>
            </p>
            <p>
                <label for="Country">Country:</label>
                <%=Html.TextBox("Country") %>
                <%=Html.ValidationMessage("Country", "*") %>
            </p>
            <p>
                <label for="ContactPhone">ContactPhone:</label>
                <%=Html.TextBox("ContactPhone") %>
                <%=Html.ValidationMessage("ContactPhone", "*") %>
            </p>            
            <p>
                <label for="Latitude">Latitude:</label>
                <%=Html.TextBox("Latitude") %>
                <%=Html.ValidationMessage("Latitude", "*") %>
            </p>
            <p>
                <label for="Longitude">Longitude:</label>
                <%=Html.TextBox("Longitude") %>
                <%=Html.ValidationMessage("Longitude", "*") %>
            </p>
            <p>
                <input type="submit" value="Save"/>
            </p>
        </fieldset>
    <% } 
%>
</asp:Content>

Et maintenant, lorsque nous exécutons notre application et accédons à l’URL « /Dinners/Create » dans le navigateur, elle affiche l’interface utilisateur comme ci-dessous à partir de notre implémentation de l’action Créer :

Capture d’écran de l’implémentation de créer une action lorsque nous exécutons notre application et accédons à Dinners U R L.

Implémentation de la méthode d’action create HTTP-POST

Nous avons implémenté la version HTTP-GET de notre méthode d’action Create. Lorsqu’un utilisateur clique sur le bouton « Enregistrer », il effectue une publication de formulaire sur l’URL /Dinners/Create et envoie les valeurs du formulaire d’entrée> HTML <à l’aide du verbe HTTP POST.

Implémentons maintenant le comportement HTTP POST de notre méthode create action. Nous allons commencer par ajouter une méthode d’action « Create » surchargée à notre DinnersController avec un attribut « AcceptVerbs » qui indique qu’elle gère les scénarios HTTP POST :

//
// POST: /Dinners/Create

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create() {
    ...
}

Il existe différentes façons d’accéder aux paramètres de formulaire publiés dans notre méthode « Créer » activée par HTTP-POST.

Une approche consiste à créer un objet Dinner, puis à utiliser la méthode d’assistance UpdateModel() (comme nous l’avons fait avec l’action Modifier) pour le remplir avec les valeurs de formulaire publiées. Nous pouvons ensuite l’ajouter à notre DinnerRepository, le conserver dans la base de données et rediriger l’utilisateur vers notre action Détails pour afficher le dîner nouvellement créé à l’aide du code ci-dessous :

//
// POST: /Dinners/Create

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create() {

    Dinner dinner = new Dinner();

    try {
    
        UpdateModel(dinner);

        dinnerRepository.Add(dinner);
        dinnerRepository.Save();

        return RedirectToAction("Details", new {id=dinner.DinnerID});
    }
    catch {
    
        ModelState.AddRuleViolations(dinner.GetRuleViolations());

        return View(dinner);
    }
}

Nous pouvons également utiliser une approche dans laquelle notre méthode d’action Create() prend un objet Dinner comme paramètre de méthode. ASP.NET MVC instancie automatiquement un nouvel objet Dinner pour nous, remplit ses propriétés à l’aide des entrées de formulaire et le transmet à notre méthode d’action :

//
//
// POST: /Dinners/Create

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Dinner dinner) {

    if (ModelState.IsValid) {

        try {
            dinner.HostedBy = "SomeUser";

            dinnerRepository.Add(dinner);
            dinnerRepository.Save();

            return RedirectToAction("Details", new {id = dinner.DinnerID });
        }
        catch {        
            ModelState.AddRuleViolations(dinner.GetRuleViolations());
        }
    }
    
    return View(dinner);
}

Notre méthode d’action ci-dessus vérifie que l’objet Dinner a été correctement rempli avec les valeurs de publication de formulaire en vérifiant la propriété ModelState.IsValid. Cette opération renvoie la valeur false en cas de problèmes de conversion d’entrée (par exemple , une chaîne « BOGUS » pour la propriété EventDate) et, en cas de problème, notre méthode d’action réaffiche le formulaire.

Si les valeurs d’entrée sont valides, la méthode d’action tente d’ajouter et d’enregistrer le nouveau Dinner dans DinnerRepository. Il encapsule ce travail dans un bloc try/catch et réaffiche le formulaire en cas de violation de règle d’entreprise (ce qui entraînerait le déclenchement d’une exception par la méthode dinnerRepository.Save().

Pour voir ce comportement de gestion des erreurs en action, nous pouvons demander l’URL /Dinners/Create et renseigner les détails d’un nouveau Dinner. Une entrée ou des valeurs incorrectes entraînent la réaffiche du formulaire de création avec les erreurs mises en surbrillance comme ci-dessous :

Capture d’écran du formulaire réaffiché avec les erreurs mises en surbrillance.

Notez que notre formulaire Créer respecte exactement les mêmes règles de validation et d’entreprise que notre formulaire Modifier. Cela est dû au fait que nos règles de validation et d’entreprise ont été définies dans le modèle et n’étaient pas incorporées dans l’interface utilisateur ou le contrôleur de l’application. Cela signifie que nous pouvons par la suite modifier/faire évoluer nos règles de validation ou d’entreprise dans un emplacement unique et les faire appliquer dans l’ensemble de notre application. Nous n’avons pas besoin de modifier le code dans nos méthodes d’action Modifier ou Créer pour respecter automatiquement les nouvelles règles ou les modifications apportées aux règles existantes.

Lorsque nous corrigeons les valeurs d’entrée et cliquez à nouveau sur le bouton « Enregistrer », notre ajout à DinnerRepository réussit, et un nouveau Dinner sera ajouté à la base de données. Nous serons ensuite redirigés vers l’URL /Dinners/Details/[id], où les détails du dîner nouvellement créé nous seront présentés :

Capture d’écran du dîner nouvellement créé.

Supprimer le support

Nous allons maintenant ajouter la prise en charge « Supprimer » à notre DinnersController.

Méthode d’action De suppression HTTP-GET

Nous allons commencer par implémenter le comportement HTTP GET de notre méthode d’action de suppression. Cette méthode est appelée lorsqu’une personne visite l’URL /Dinners/Delete/[id]. Voici l’implémentation :

//
// HTTP GET: /Dinners/Delete/1

public ActionResult Delete(int id) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    if (dinner == null)
         return View("NotFound");
    else
        return View(dinner);
}

La méthode d’action tente de récupérer le Dinner à supprimer. Si le dinner existe, il affiche une vue basée sur l’objet Dinner. Si l’objet n’existe pas (ou a déjà été supprimé), il retourne une vue qui restitue le modèle d’affichage « NotFound » que nous avons créé précédemment pour notre méthode d’action « Details ».

Nous pouvons créer le modèle d’affichage « Supprimer » en cliquant avec le bouton droit dans la méthode d’action Delete et en sélectionnant la commande de menu contextuel « Ajouter une vue ». Dans la boîte de dialogue « Ajouter une vue », nous allons indiquer que nous transmettons un objet Dinner à notre modèle d’affichage en tant que modèle et que nous choisissons de créer un modèle vide :

Capture d’écran de la création du modèle d’affichage Supprimer en tant que modèle vide.

Lorsque nous cliquons sur le bouton « Ajouter », Visual Studio ajoute un nouveau fichier de modèle d’affichage « Delete.aspx » pour nous dans notre répertoire « \Views\Dinners ». Nous allons ajouter du code html et du code au modèle pour implémenter un écran de confirmation de suppression comme ci-dessous :

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Delete Confirmation:  <%=Html.Encode(Model.Title) %>
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>
        Delete Confirmation
    </h2>

    <div>
        <p>Please confirm you want to cancel the dinner titled: 
           <i> <%=Html.Encode(Model.Title) %>? </i> 
        </p>
    </div>
    
    <% using (Html.BeginForm()) {  %>
        <input name="confirmButton" type="submit" value="Delete" />        
    <% } %>
     
</asp:Content>

Le code ci-dessus affiche le titre du Dinner à supprimer et génère un <élément de formulaire> qui effectue une opération POST vers l’URL /Dinners/Delete/[id] si l’utilisateur final clique sur le bouton « Supprimer » qu’il contient.

Lorsque nous exécutons notre application et accédons à l’URL « /Dinners/Delete/[id] » pour un objet Dinner valide, elle affiche l’interface utilisateur comme ci-dessous :

Capture d’écran de la confirmation de suppression du dîner U I dans la méthode d’action H T T P G E T Delete.

Rubrique latérale : Pourquoi faisons-nous un POST ?
Vous pouvez vous demander pourquoi avons-nous fait l’effort de créer un <formulaire> dans notre écran de confirmation Supprimer ? Pourquoi ne pas simplement utiliser un lien hypertexte standard pour établir un lien vers une méthode d’action qui effectue l’opération de suppression réelle ? La raison en est que nous voulons être prudents contre les robots web et les moteurs de recherche qui découvrent nos URL et provoquent par inadvertance la suppression des données lorsqu’ils suivent les liens. Les URL basées sur HTTP-GET sont considérées comme « sécurisées » pour leur accès/analyse, et elles sont censées ne pas suivre celles http-POST. Une bonne règle consiste à veiller à toujours placer les opérations destructives ou de modification des données derrière les requêtes HTTP-POST.

Implémentation de la méthode d’action HTTP-POST Delete

Nous avons maintenant implémenté la version HTTP-GET de notre méthode d’action Delete qui affiche un écran de confirmation de suppression. Lorsqu’un utilisateur final clique sur le bouton « Supprimer », il effectue une publication de formulaire sur l’URL /Dinners/Dinner/[id].

Implémentons maintenant le comportement HTTP « POST » de la méthode d’action de suppression à l’aide du code ci-dessous :

// 
// HTTP POST: /Dinners/Delete/1

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(int id, string confirmButton) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    if (dinner == null)
        return View("NotFound");

    dinnerRepository.Delete(dinner);
    dinnerRepository.Save();

    return View("Deleted");
}

La version HTTP-POST de notre méthode d’action Delete tente de récupérer l’objet dinner à supprimer. S’il ne le trouve pas (car il a déjà été supprimé), il restitue notre modèle « NotFound ». S’il trouve le Dîner, il le supprime du DinnerRepository. Il restitue ensuite un modèle « Supprimé ».

Pour implémenter le modèle « Supprimé », nous allons cliquer avec le bouton droit dans la méthode d’action et choisir le menu contextuel « Ajouter une vue ». Nous allons nommer notre vue « Supprimé » et lui faire en sorte qu’il s’agit d’un modèle vide (sans prendre un objet de modèle fortement typé). Nous allons ensuite y ajouter du contenu HTML :

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    Dinner Deleted
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Dinner Deleted</h2>

    <div>
        <p>Your dinner was successfully deleted.</p>
    </div>
    
    <div>
        <p><a href="/dinners">Click for Upcoming Dinners</a></p>
    </div>
    
</asp:Content>

Et maintenant, lorsque nous exécutons notre application et accédons à l’URL « /Dinners/Delete/[id] » pour un objet Dinner valide, l’écran de confirmation de la suppression du dîner s’affiche comme ci-dessous :

Capture d’écran de l’écran de confirmation de la suppression du dîner dans la méthode d’action H TT P O ST Delete.

Lorsque nous cliquons sur le bouton « Supprimer », il effectue une opération HTTP-POST sur l’URL /Dinners/Delete/[id], ce qui supprime le dîner de notre base de données et affiche notre modèle d’affichage « Supprimé » :

Capture d’écran du modèle d’affichage supprimé.

Sécurité de la liaison de modèle

Nous avons abordé deux façons différentes d’utiliser les fonctionnalités de liaison de modèles intégrées de ASP.NET MVC. La première qui utilise la méthode UpdateModel() pour mettre à jour les propriétés d’un objet de modèle existant, et la seconde qui utilise ASP.NET la prise en charge de MVC pour passer des objets de modèle en tant que paramètres de méthode d’action. Ces deux techniques sont très puissantes et extrêmement utiles.

Ce pouvoir entraîne également une responsabilité. Il est important de toujours être paranoïaque en ce qui concerne la sécurité lors de l’acceptation d’une entrée utilisateur, et cela est également vrai lors de la liaison d’objets pour former une entrée. Veillez à toujours encoder au format HTML toutes les valeurs entrées par l’utilisateur afin d’éviter les attaques par injection de code HTML et JavaScript, et faites attention aux attaques par injection de code SQL (remarque : nous utilisons LINQ to SQL pour notre application, qui encode automatiquement les paramètres pour empêcher ces types d’attaques). Vous ne devez jamais vous appuyer uniquement sur la validation côté client et toujours utiliser la validation côté serveur pour vous protéger contre les pirates informatiques qui tentent de vous envoyer des valeurs fausses.

Un élément de sécurité supplémentaire à prendre en compte lors de l’utilisation des fonctionnalités de liaison de ASP.NET MVC est l’étendue des objets que vous liez. Plus précisément, vous souhaitez vous assurer que vous comprenez les implications en matière de sécurité des propriétés que vous autorisez à être liées et que vous autorisez uniquement les propriétés qui doivent vraiment être mises à jour par un utilisateur final.

Par défaut, la méthode UpdateModel() tente de mettre à jour toutes les propriétés de l’objet de modèle qui correspondent aux valeurs des paramètres de formulaire entrants. De même, les objets passés en tant que paramètres de méthode d’action peuvent également avoir par défaut toutes leurs propriétés définies via des paramètres de formulaire.

Verrouillage de la liaison par utilisation

Vous pouvez verrouiller la stratégie de liaison par utilisation en fournissant une « liste d’inclure » explicite des propriétés qui peuvent être mises à jour. Pour ce faire, passez un paramètre de tableau de chaînes supplémentaire à la méthode UpdateModel() comme ci-dessous :

string[] allowedProperties = new[]{ "Title","Description", 
                                    "ContactPhone", "Address",
                                    "EventDate", "Latitude", 
                                    "Longitude"};
                                    
UpdateModel(dinner, allowedProperties);

Les objets passés en tant que paramètres de méthode d’action prennent également en charge un attribut [Bind] qui permet de spécifier une « liste d’inclure » des propriétés autorisées comme ci-dessous :

//
// POST: /Dinners/Create

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create( [Bind(Include="Title,Address")] Dinner dinner ) {
    ...
}

Verrouillage de la liaison sur une base de type

Vous pouvez également verrouiller les règles de liaison par type. Cela vous permet de spécifier les règles de liaison une seule fois, puis de les appliquer dans tous les scénarios (y compris les scénarios UpdateModel et les scénarios de paramètres de méthode d’action) sur tous les contrôleurs et méthodes d’action.

Vous pouvez personnaliser les règles de liaison par type en ajoutant un attribut [Bind] à un type ou en l’inscrivant dans le fichier Global.asax de l’application (utile pour les scénarios où vous ne possédez pas le type). Vous pouvez ensuite utiliser les propriétés Include et Exclude de l’attribut Bind pour contrôler les propriétés pouvant être liées pour la classe ou l’interface particulière.

Nous allons utiliser cette technique pour la classe Dinner dans notre application NerdDinner et y ajouter un attribut [Bind] qui limite la liste des propriétés pouvant être liées aux éléments suivants :

[Bind(Include="Title,Description,EventDate,Address,Country,ContactPhone,Latitude,Longitude")]
public partial class Dinner {
   ...
}

Notez que nous n’autoréparons pas la manipulation de la collection RSVPs via la liaison, ni la définition des propriétés DinnerID ou HostedBy via la liaison. Pour des raisons de sécurité, nous allons uniquement manipuler ces propriétés particulières à l’aide de code explicite dans nos méthodes d’action.

Wrap-Up CRUD

ASP.NET MVC inclut un certain nombre de fonctionnalités intégrées qui permettent d’implémenter des scénarios de publication de formulaire. Nous avons utilisé une variété de ces fonctionnalités pour fournir la prise en charge de l’interface utilisateur CRUD en plus de notre DinnerRepository.

Nous utilisons une approche axée sur les modèles pour implémenter notre application. Cela signifie que toute notre logique de validation et de règle métier est définie dans notre couche de modèle, et non dans nos contrôleurs ou vues. Ni notre classe contrôleur ni nos modèles d’affichage ne connaissent les règles métier spécifiques appliquées par notre classe de modèle Dinner.

Cela permet de garder notre architecture d’application propre et de faciliter les tests. Nous pouvons ajouter des règles d’entreprise supplémentaires à notre couche de modèle à l’avenir et ne pas avoir à apporter de modifications de code à notre contrôleur ou à notre vue pour qu’elles soient prises en charge. Cela nous fournira une grande agilité pour évoluer et changer notre application à l’avenir.

Notre DinnersController active désormais les descriptions/détails du dîner, ainsi que la création, la modification et la suppression de la prise en charge. Le code complet de la classe est disponible ci-dessous :

public class DinnersController : Controller {

    DinnerRepository dinnerRepository = new DinnerRepository();

    //
    // GET: /Dinners/

    public ActionResult Index() {

        var dinners = dinnerRepository.FindUpcomingDinners().ToList();
        return View(dinners);
    }

    //
    // GET: /Dinners/Details/2

    public ActionResult Details(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View(dinner);
    }

    //
    // GET: /Dinners/Edit/2

    public ActionResult Edit(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);
        return View(dinner);
    }

    //
    // POST: /Dinners/Edit/2

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(int id, FormCollection formValues) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        try {
            UpdateModel(dinner);

            dinnerRepository.Save();

            return RedirectToAction("Details", new { id= dinner.DinnerID });
        }
        catch {
            ModelState.AddRuleViolations(dinner.GetRuleViolations());

            return View(dinner);
        }
    }

    //
    // GET: /Dinners/Create

    public ActionResult Create() {

        Dinner dinner = new Dinner() {
            EventDate = DateTime.Now.AddDays(7)
        };
        return View(dinner);
    }

    //
    // POST: /Dinners/Create

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(Dinner dinner) {

        if (ModelState.IsValid) {

            try {
                dinner.HostedBy = "SomeUser";

                dinnerRepository.Add(dinner);
                dinnerRepository.Save();

                return RedirectToAction("Details", new{id=dinner.DinnerID});
            }
            catch {
                ModelState.AddRuleViolations(dinner.GetRuleViolations());
            }
        }

        return View(dinner);
    }

    //
    // HTTP GET: /Dinners/Delete/1

    public ActionResult Delete(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (dinner == null)
            return View("NotFound");
        else
            return View(dinner);
    }

    // 
    // HTTP POST: /Dinners/Delete/1

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Delete(int id, string confirmButton) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (dinner == null)
            return View("NotFound");

        dinnerRepository.Delete(dinner);
        dinnerRepository.Save();

        return View("Deleted");
    }
}

étape suivante

Nous avons maintenant la prise en charge cruD de base (Create, Read, Update et Delete) implémentée dans notre classe DinnersController.

Voyons maintenant comment utiliser les classes ViewData et ViewModel pour activer une interface utilisateur encore plus riche sur nos formulaires.