Application à une seule page : modèle KnockoutJS
Le modèle Knockout MVC fait partie de ASP.NET et Web Tools 2012.2
La mise à jour ASP.NET et Web Tools 2012.2 inclut un modèle d’application Single-Page (SPA) pour ASP.NET MVC 4. Ce modèle est conçu pour vous aider à créer rapidement des applications web interactives côté client.
« Application monopage » (SPA) est le terme général d’une application web qui charge une seule page HTML, puis met à jour la page dynamiquement, au lieu de charger de nouvelles pages. Après le chargement initial de la page, le spa communique avec le serveur via des requêtes AJAX.
AJAX n’est rien de nouveau, mais il existe aujourd’hui des frameworks JavaScript qui facilitent la création et la maintenance d’une grande application SPA sophistiquée. En outre, HTML 5 et CSS3 facilitent la création d’interfaces utilisateur enrichies.
Pour commencer, le modèle SPA crée un exemple d’application de liste de tâches. Dans ce tutoriel, nous allons suivre une visite guidée du modèle. Nous allons tout d’abord examiner l’application de liste de tâches elle-même, puis examiner les éléments technologiques qui la font fonctionner.
Créer un projet de modèle SPA
Conditions requises :
- Visual Studio 2012 ou Visual Studio Express 2012 pour le web
- ASP.NET mise à jour de Web Tools 2012.2. Vous pouvez installer la mise à jour ici.
Démarrez Visual Studio et sélectionnez Nouveau projet dans la page Démarrer. Ou, dans le menu Fichier , sélectionnez Nouveau , puis Projet.
Dans le volet Modèles , sélectionnez Modèles installés et développez le nœud Visual C# . Sous Visual C#, sélectionnez Web. Dans la liste des modèles de projet, sélectionnez ASP.NET application web MVC 4. Nommez le projet, puis cliquez sur OK.
Dans l’Assistant Nouveau projet , sélectionnez Application monopage.
Appuyez sur F5 pour générer et exécuter l’application. Lorsque l’application s’exécute pour la première fois, elle affiche un écran de connexion.
Cliquez sur le lien « S’inscrire » et créez un utilisateur.
Une fois connecté, l’application crée une liste todo par défaut avec deux éléments. Vous pouvez cliquer sur « Ajouter une liste de tâches » pour ajouter une nouvelle liste.
Renommez la liste, ajoutez des éléments à la liste et case activée-les. Vous pouvez également supprimer des éléments ou supprimer une liste entière. Les modifications sont automatiquement conservées dans une base de données sur le serveur (en fait LocalDB à ce stade, car vous exécutez l’application localement).
Architecture du modèle SPA
Ce diagramme montre les main blocs de construction de l’application.
Côté serveur, ASP.NET MVC sert le code HTML et gère également l’authentification basée sur les formulaires.
API Web ASP.NET gère toutes les demandes liées aux ToDoLists et ToDoItems, y compris l’obtention, la création, la mise à jour et la suppression. Le client échange des données avec l’API web au format JSON.
Entity Framework (EF) est la couche O/RM. Il intermédiat entre le monde orienté objet de ASP.NET et la base de données sous-jacente. La base de données utilise LocalDB, mais vous pouvez le modifier dans le fichier Web.config. En règle générale, vous utilisez LocalDB pour le développement local, puis vous déployez sur une base de données SQL sur le serveur, à l’aide de la migration ef code-first.
Côté client, la bibliothèque Knockout.js gère les mises à jour des pages à partir des requêtes AJAX. Knockout utilise la liaison de données pour synchroniser la page avec les données les plus récentes. De cette façon, vous n’avez pas besoin d’écrire le code qui parcoure les données JSON et met à jour le DOM. Au lieu de cela, vous placez des attributs déclaratifs dans le code HTML qui indiquent à Knockout comment présenter les données.
Un grand avantage de cette architecture est qu’elle sépare la couche de présentation de la logique d’application. Vous pouvez créer la partie API web sans savoir à quoi ressemblera votre page web. Côté client, vous créez un « modèle d’affichage » pour représenter ces données, et le modèle de vue utilise Knockout pour la liaison au code HTML. Cela vous permet de modifier facilement le code HTML sans modifier le modèle d’affichage. (Nous allons voir Knockout un peu plus tard.)
Modèles
Dans le projet Visual Studio, le dossier Models contient les modèles utilisés côté serveur. (Il existe également des modèles côté client; nous allons y accéder.)
TodoItem, TodoList
Il s’agit des modèles de base de données pour Entity Framework Code First. Notez que ces modèles ont des propriétés qui pointent les uns vers les autres. ToDoList
contient une collection de ToDoItems, et chacun ToDoItem
a une référence à son toDoList parent. Ces propriétés sont appelées propriétés de navigation, et elles représentent la relation un-à-plusieurs une liste de tâches et ses éléments de tâches.
La ToDoItem
classe utilise également l’attribut [ForeignKey] pour spécifier que ToDoListId
est une clé étrangère dans la ToDoList
table. Cela indique à EF d’ajouter une contrainte de clé étrangère à la base de données.
[ForeignKey("TodoList")]
public int TodoListId { get; set; }
public virtual TodoList TodoList { get; set; }
TodoItemDto, TodoListDto
Ces classes définissent les données qui seront envoyées au client. « DTO » signifie « objet de transfert de données ». Le DTO définit la façon dont les entités seront sérialisées au format JSON. En général, il existe plusieurs raisons d’utiliser des DTO :
- Pour contrôler les propriétés sérialisées. Le DTO peut contenir un sous-ensemble des propriétés du modèle de domaine. Vous pouvez le faire pour des raisons de sécurité (pour masquer des données sensibles) ou simplement pour réduire la quantité de données que vous envoyez.
- Pour modifier la forme des données, par exemple pour aplatir une structure de données plus complexe.
- Pour empêcher toute logique métier d’être en dehors du DTO (séparation des préoccupations).
- Si vos modèles de domaine ne peuvent pas être sérialisés pour une raison quelconque. Par exemple, les références circulaires peuvent entraîner des problèmes lorsque vous sérialisez un objet Il existe des moyens de gérer ce problème dans l’API web (voir Gestion des références d’objets circulaires) ; mais l’utilisation d’un DTO évite tout simplement le problème.
Dans le modèle SPA, les DTO contiennent les mêmes données que les modèles de domaine. Toutefois, elles restent utiles, car elles évitent les références circulaires à partir des propriétés de navigation et illustrent le modèle DTO général.
AccountModels.cs
Ce fichier contient des modèles pour l’appartenance au site. La UserProfile
classe définit le schéma des profils utilisateur dans la base de données d’appartenance. (Dans ce cas, les seules informations sont l’ID utilisateur et le nom d’utilisateur.) Les autres classes de modèle de ce fichier sont utilisées pour créer les formulaires d’inscription et de connexion de l’utilisateur.
Entity Framework
Le modèle SPA utilise EF Code First. Dans le développement Code First, vous définissez d’abord les modèles dans le code, puis EF utilise le modèle pour créer la base de données. Vous pouvez également utiliser EF avec une base de données existante (Base de données d’abord).
La TodoItemContext
classe dans le dossier Models dérive de DbContext. Cette classe fournit la « colle » entre les modèles et EF. contient TodoItemContext
une ToDoItem
collection et une TodoList
collection. Pour interroger la base de données, il vous suffit d’écrire une requête LINQ sur ces collections. Par exemple, voici comment sélectionner toutes les listes de tâches pour l’utilisateur « Alice » :
TodoItemContext db = new TodoItemContext();
IEnumerable<TodoList> lists =
from td in db.TodoLists where td.UserId == "Alice" select td;
Vous pouvez également ajouter de nouveaux éléments à la collection, mettre à jour des éléments ou supprimer des éléments de la collection, et conserver les modifications apportées à la base de données.
contrôleurs API Web ASP.NET
Dans API Web ASP.NET, les contrôleurs sont des objets qui gèrent les requêtes HTTP. Comme mentionné précédemment, le modèle SPA utilise l’API web pour activer les opérations CRUD sur ToDoList
les instances et ToDoItem
. Les contrôleurs se trouvent dans le dossier Contrôleurs de la solution.
TodoController
: gère les requêtes HTTP pour les éléments à faireTodoListController
: gère les requêtes HTTP pour les listes de tâches.
Ces noms sont significatifs, car l’API web correspond au chemin d’ACCÈS URI au nom du contrôleur. (Pour savoir comment l’API web achemine les requêtes HTTP vers les contrôleurs, consultez Routage dans API Web ASP.NET.)
Examinons la ToDoListController
classe. Il contient un seul membre de données :
private TodoItemContext db = new TodoItemContext();
TodoItemContext
est utilisé pour communiquer avec EF, comme décrit précédemment. Les méthodes du contrôleur implémentent les opérations CRUD. L’API web mappe les requêtes HTTP du client aux méthodes de contrôleur, comme suit :
Demande HTTP | Controller, méthode | Description |
---|---|---|
GET /api/todo | GetTodoLists |
Obtient une collection de listes de tâches. |
GET /api/todo/id | GetTodoList |
Obtient une liste de tâches par ID |
PUT /api/todo/id | PutTodoList |
Mises à jour une liste de tâches. |
POST /api/todo | PostTodoList |
Crée une liste de tâches. |
DELETE /api/todo/id | DeleteTodoList |
Supprime une liste TODO. |
Notez que les URI de certaines opérations contiennent des espaces réservés pour la valeur d’ID. Par exemple, pour supprimer une liste de to avec l’ID 42, l’URI est /api/todo/42
.
Pour en savoir plus sur l’utilisation de l’API web pour les opérations CRUD, consultez Création d’une API web qui prend en charge les opérations CRUD. Le code de ce contrôleur est assez simple. Voici quelques points intéressants :
- La
GetTodoLists
méthode utilise une requête LINQ pour filtrer les résultats en fonction de l’ID de l’utilisateur connecté. De cette façon, un utilisateur ne voit que les données qui lui appartiennent. Notez également qu’une instruction Select est utilisée pour convertir lesToDoList
instances enTodoListDto
instances. - Les méthodes PUT et POST case activée l’état du modèle avant de modifier la base de données. Si ModelState.IsValid a la valeur false, ces méthodes retournent HTTP 400, Requête incorrecte. Pour en savoir plus sur la validation des modèles dans API web, consultez Validation du modèle.
- La classe de contrôleur est également décorée avec l’attribut [Authorize]. Cet attribut vérifie si la requête HTTP est authentifiée. Si la demande n’est pas authentifiée, le client reçoit HTTP 401, Non autorisé. Pour en savoir plus sur l’authentification, consultez Authentification et autorisation dans API Web ASP.NET.
La TodoController
classe est très similaire à TodoListController
. La plus grande différence est qu’il ne définit aucune méthode GET, car le client obtient les éléments à faire avec chaque liste de tâches.
Vues et contrôleurs MVC
Les contrôleurs MVC se trouvent également dans le dossier Contrôleurs de la solution. HomeController
affiche le code HTML main de l’application. La vue du contrôleur de base est définie dans Views/Home/Index.cshtml. La vue Accueil affiche un contenu différent selon que l’utilisateur est connecté ou non :
@if (@User.Identity.IsAuthenticated)
{
// ....
}
Lorsque les utilisateurs sont connectés, ils voient l’interface utilisateur main. Sinon, ils voient le panneau de connexion. Notez que ce rendu conditionnel se produit côté serveur. N’essayez jamais de masquer du contenu sensible côté client: tout ce que vous envoyez dans une réponse HTTP est visible par quelqu’un qui regarde les messages HTTP bruts.
Client-Side JavaScript et Knockout.js
Nous allons maintenant passer du côté serveur de l’application au client. Le modèle SPA utilise une combinaison de jQuery et de Knockout.js pour créer une interface utilisateur fluide et interactive. Knockout.js est une bibliothèque JavaScript qui facilite la liaison du code HTML à des données. Knockout.js utilise un modèle appelé « Model-ViewModel ».
- Le modèle est les données de domaine (listes ToDo et éléments ToDo).
- La vue est le document HTML.
- Le modèle de vue est un objet JavaScript qui contient les données du modèle. Le modèle d’affichage est une abstraction de code de l’interface utilisateur. Il n’a aucune connaissance de la représentation HTML. Au lieu de cela, il représente des fonctionnalités abstraites de la vue, telles que « une liste d’éléments ToDo ».
La vue est liée aux données du modèle d’affichage. Mises à jour au modèle d’affichage sont automatiquement répercutés dans la vue. Les liaisons fonctionnent également dans l’autre sens. Les événements du DOM (tels que les clics) sont liés aux données aux fonctions du modèle d’affichage, qui déclenchent des appels AJAX.
Le modèle SPA organise le Code JavaScript côté client en trois couches :
- todo.datacontext.js : envoie les requêtes AJAX.
- todo.model.js : définit les modèles.
- todo.viewmodel.js : définit le modèle d’affichage.
Ces fichiers de script se trouvent dans le dossier Scripts/application de la solution.
todo.datacontext gère tous les appels AJAX aux contrôleurs d’API web. (Les appels AJAX pour la connexion sont définis ailleurs, dans ajaxlogin.js.)
todo.model.js définit les modèles côté client (navigateur) pour les listes de tâches. Il existe deux classes de modèle : todoItem et todoList.
La plupart des propriétés des classes de modèle sont de type « ko.observable ». Les observables sont la façon dont Knockout fait sa magie. Dans la documentation Knockout : Une observable est un « objet JavaScript qui peut informer les abonnés des modifications ». Lorsque la valeur d’une observable change, Knockout met à jour tous les éléments HTML liés à ces observables. Par exemple, todoItem a des observables pour les propriétés title et isDone :
self.title = ko.observable(data.title);
self.isDone = ko.observable(data.isDone);
Vous pouvez également vous abonner à un observable dans le code. Par exemple, la classe todoItem s’abonne aux modifications apportées aux propriétés « isDone » et « title » :
saveChanges = function () {
return datacontext.saveChangedTodoItem(self);
};
// Auto-save when these properties change
self.isDone.subscribe(saveChanges);
self.title.subscribe(saveChanges);
Afficher le modèle
Le modèle d’affichage est défini dans todo.viewmodel.js. Le modèle d’affichage est le point central où l’application lie les éléments de page HTML aux données de domaine. Dans le modèle SPA, le modèle d’affichage contient un tableau observable de todoLists. Le code suivant dans le modèle d’affichage indique à Knockout d’appliquer les liaisons :
ko.applyBindings(window.todoApp.todoListViewModel);
HTML et liaison de données
Le code HTML main de la page est défini dans Views/Home/Index.cshtml. Étant donné que nous utilisons la liaison de données, le code HTML n’est qu’un modèle pour ce qui est réellement rendu. Knockout utilise des liaisons déclaratives . Vous liez des éléments de page à des données en ajoutant un attribut « data-bind » à l’élément. Voici un exemple très simple, tiré de la documentation de Knockout :
<p>There are <span data-bind="text: myItems().count"></span> items<p>
Dans cet exemple, Knockout met à jour le contenu de l’élément <span> avec la valeur .myItems.count()
Chaque fois que cette valeur change, Knockout met à jour le document.
Knockout fournit un certain nombre de types de liaison différents. Voici quelques-unes des liaisons utilisées dans le modèle SPA :
- foreach : vous permet d’itérer à travers une boucle et d’appliquer le même balisage à chaque élément de la liste. Il est utilisé pour afficher les listes de tâches et les éléments à faire. Dans le foreach, les liaisons sont appliquées aux éléments de la liste.
- visible : permet de désactiver la visibilité. Masquer le balisage lorsqu’une collection est vide ou rendre le message d’erreur visible.
- value : utilisé pour remplir des valeurs de formulaire.
- click : lie un événement click à une fonction sur le modèle d’affichage.
Anti-CSRF Protection
La falsification de requête intersite (CSRF) est une attaque par laquelle un site malveillant envoie une requête à un site vulnérable où l’utilisateur est actuellement connecté. Pour empêcher les attaques CSRF, ASP.NET MVC utilise des jetons anti-falsification, également appelés jetons de vérification des demandes. L’idée est que le serveur place un jeton généré de manière aléatoire dans une page web. Lorsque le client envoie des données au serveur, il doit inclure cette valeur dans le message de demande.
Les jetons anti-falsification fonctionnent parce que la page malveillante ne peut pas lire les jetons de l’utilisateur, en raison de stratégies de même origine. (Les stratégies de même origine empêchent les documents hébergés sur deux sites différents d’accéder au contenu de l’autre.)
ASP.NET MVC fournit une prise en charge intégrée des jetons anti-falsification, via la classe AntiForgery et l’attribut [ValidateAntiForgeryToken]. Actuellement, cette fonctionnalité n’est pas intégrée à l’API web. Toutefois, le modèle SPA inclut une implémentation personnalisée pour l’API web. Ce code est défini dans la ValidateHttpAntiForgeryTokenAttribute
classe, qui se trouve dans le dossier Filtres de la solution. Pour en savoir plus sur l’anti-CSRF dans l’API web, consultez Prévention des attaques par falsification de requête intersite (CSRF).
Conclusion
Le modèle SPA est conçu pour vous aider à commencer rapidement à écrire des applications web modernes et interactives. Il utilise la bibliothèque Knockout.js pour séparer la présentation (balisage HTML) de la logique des données et de l’application. Mais Knockout n’est pas la seule bibliothèque JavaScript que vous pouvez utiliser pour créer un SPA. Si vous souhaitez explorer d’autres options, consultez les modèles SPA créés par la communauté.