Mise en cache de données au démarrage de l’application (C#)
par Scott Mitchell
Dans n’importe quelle application web, certaines données seront fréquemment utilisées et certaines données seront rarement utilisées. Nous pouvons améliorer les performances de notre application ASP.NET en chargeant à l’avance les données fréquemment utilisées, une technique appelée Mise en cache. Ce tutoriel présente une approche du chargement proactif, qui consiste à charger des données dans le cache au démarrage de l’application.
Introduction
Les deux didacticiels précédents ont examiné la mise en cache des données dans les couches Présentation et Mise en cache. Dans Mise en cache des données avec ObjectDataSource, nous avons examiné l’utilisation des fonctionnalités de mise en cache d’ObjectDataSource pour mettre en cache les données dans la couche de présentation. La mise en cache des données dans l’architecture a examiné la mise en cache dans une nouvelle couche de mise en cache distincte. Ces deux didacticiels utilisaient le chargement réactif lors de l’utilisation du cache de données. Avec le chargement réactif, chaque fois que les données sont demandées, le système vérifie d’abord si elles se trouve dans le cache. Si ce n’est pas le cas, il récupère les données de la source d’origine, telle que la base de données, puis les stocke dans le cache. L’avantage main du chargement réactif est sa facilité d’implémentation. L’un de ses inconvénients est ses performances inégales entre les requêtes. Imaginez une page qui utilise la couche de mise en cache du tutoriel précédent pour afficher des informations sur le produit. Lorsque cette page est visitée pour la première fois, ou la première fois après que les données mises en cache ont été supprimées en raison de contraintes de mémoire ou de l’expiration spécifiée ayant été atteinte, les données doivent être récupérées de la base de données. Par conséquent, ces demandes d’utilisateurs prendront plus de temps que les demandes des utilisateurs qui peuvent être traitées par le cache.
Le chargement proactif fournit une autre stratégie de gestion du cache qui lisser les performances entre les requêtes en chargeant les données mises en cache avant qu’elles ne s’avèrent nécessaires. En règle générale, le chargement proactif utilise un processus qui vérifie régulièrement ou est averti lorsqu’une mise à jour des données sous-jacentes a été effectuée. Ce processus met ensuite à jour le cache pour le garder à jour. Le chargement proactif est particulièrement utile si les données sous-jacentes proviennent d’une connexion de base de données lente, d’un service Web ou d’une autre source de données particulièrement lente. Toutefois, cette approche du chargement proactif est plus difficile à implémenter, car elle nécessite la création, la gestion et le déploiement d’un processus pour case activée des modifications et mettre à jour le cache.
Une autre saveur de chargement proactif, et le type que nous allons explorer dans ce tutoriel, est le chargement de données dans le cache au démarrage de l’application. Cette approche est particulièrement utile pour mettre en cache des données statiques, telles que les enregistrements dans les tables de recherche de base de données.
Notes
Pour plus d’informations sur les différences entre le chargement proactif et réactif, ainsi que sur les listes des avantages, des inconvénients et des recommandations d’implémentation, reportez-vous à la section Gestion du contenu d’un cache du Guide d’architecture de mise en cache pour les applications .NET Framework.
Étape 1 : Détermination des données à mettre en cache au démarrage de l’application
Les exemples de mise en cache utilisant le chargement réactif que nous avons examinés dans les deux tutoriels précédents fonctionnent bien avec des données qui peuvent changer périodiquement et ne prennent pas de temps exorbitant à générer. Mais si les données mises en cache ne changent jamais, l’expiration utilisée par le chargement réactif est superflue. De même, si la génération des données mises en cache prend beaucoup de temps, les utilisateurs dont les demandes trouvent le cache vide devront supporter une longue attente pendant la récupération des données sous-jacentes. Envisagez de mettre en cache des données statiques et des données qui prennent un temps exceptionnellement long à générer au démarrage de l’application.
Bien que les bases de données aient de nombreuses valeurs dynamiques qui changent fréquemment, la plupart ont également une bonne quantité de données statiques. Par exemple, pratiquement tous les modèles de données ont une ou plusieurs colonnes qui contiennent une valeur particulière d’un ensemble fixe de choix. Une Patients
table de base de données peut avoir une PrimaryLanguage
colonne, dont l’ensemble de valeurs peut être anglais, espagnol, Français, russe, japonais, etc. Souvent, ces types de colonnes sont implémentés à l’aide de tables de recherche. Au lieu de stocker la chaîne en anglais ou Français dans la Patients
table, une deuxième table est créée avec, généralement, deux colonnes - un identificateur unique et une description de chaîne - avec un enregistrement pour chaque valeur possible. La PrimaryLanguage
colonne de la Patients
table stocke l’identificateur unique correspondant dans la table de recherche. Dans la figure 1, la langue principale du patient John Doe est l’anglais, tandis que la langue d’Ed Johnson est le russe.
Figure 1 : La Languages
table est une table de recherche utilisée par la Patients
table
L’interface utilisateur permettant de modifier ou de créer un nouveau patient comprend une liste déroulante de langues autorisées remplie par les enregistrements dans la Languages
table. Sans mise en cache, chaque fois que cette interface est visitée, le système doit interroger la Languages
table. C’est inutile et inutile, car les valeurs de la table de recherche changent très rarement, voire jamais.
Nous pourrions mettre en cache les données à l’aide Languages
des mêmes techniques de chargement réactif examinées dans les tutoriels précédents. Le chargement réactif, toutefois, utilise une expiration basée sur le temps, qui n’est pas nécessaire pour les données de table de recherche statiques. Bien que la mise en cache à l’aide du chargement réactif soit préférable à l’absence de mise en cache, la meilleure approche consisterait à charger de manière proactive les données de la table de recherche dans le cache au démarrage de l’application.
Dans ce tutoriel, nous allons voir comment mettre en cache des données de table de recherche et d’autres informations statiques.
Étape 2 : Examen des différentes façons de mettre en cache les données
Les informations peuvent être mises en cache par programme dans une application ASP.NET à l’aide de diverses approches. Nous avons déjà vu comment utiliser le cache de données dans les tutoriels précédents. Vous pouvez également mettre en cache des objets par programmation à l’aide de membres statiques ou d’un état d’application.
Lors de l’utilisation d’une classe, la classe doit généralement être instanciée avant d’accéder à ses membres. Par exemple, pour appeler une méthode à partir de l’une des classes de notre couche logique métier, nous devons d’abord créer une instance de la classe :
ProductsBLL productsAPI = new ProductsBLL();
productsAPI.SomeMethod();
productsAPI.SomeProperty = "Hello, World!";
Avant d’appeler SomeMethod ou d’utiliser SomeProperty, nous devons d’abord créer une instance de la classe à l’aide du new
mot clé. SomeMethod et SomeProperty sont associés à un instance particulier. La durée de vie de ces membres est liée à la durée de vie de leur objet associé. Les membres statiques, d’autre part, sont des variables, des propriétés et des méthodes qui sont partagées entre toutes les instances de la classe et, par conséquent, ont une durée de vie aussi longue que la classe. Les membres statiques sont indiqués par le mot clé static
.
En plus des membres statiques, les données peuvent être mises en cache à l’aide de l’état de l’application. Chaque application ASP.NET gère une collection nom/valeur partagée entre tous les utilisateurs et pages de l’application. Cette collection est accessible à l’aide de la propriété deApplication
la HttpContext
classe et utilisée à partir de la classe code-behind d’une page ASP.NET, comme suit :
Application["key"] = value;
object value = Application["key"];
Le cache de données fournit une API beaucoup plus riche pour la mise en cache des données, fournissant des mécanismes pour les expirations basées sur le temps et les dépendances, les priorités des éléments de cache, etc. Avec les membres statiques et l’état de l’application, ces fonctionnalités doivent être ajoutées manuellement par le développeur de page. Toutefois, lors de la mise en cache des données au démarrage de l’application pendant la durée de vie de l’application, les avantages du cache de données sont sans appel. Dans ce tutoriel, nous allons examiner le code qui utilise les trois techniques de mise en cache des données statiques.
Étape 3 : Mise en cache des données deSuppliers
table
Les tables de base de données Northwind que nous avons implémentées à ce jour n’incluent aucune table de recherche traditionnelle. Les quatre DataTables implémentées dans notre DAL sont toutes les tables de modèles dont les valeurs ne sont pas statiques. Plutôt que de passer le temps d’ajouter un nouveau DataTable au DAL, puis une nouvelle classe et de nouvelles méthodes au BLL, pour ce tutoriel, nous allons simplement prétendre que les données de la Suppliers
table sont statiques. Par conséquent, nous pouvons mettre en cache ces données au démarrage de l’application.
Pour commencer, créez une classe nommée StaticCache.cs
dans le CL
dossier .
Figure 2 : Créer la StaticCache.cs
classe dans le CL
dossier
Nous devons ajouter une méthode qui charge les données au démarrage dans le magasin de cache approprié, ainsi que des méthodes qui retournent les données de ce cache.
[System.ComponentModel.DataObject]
public class StaticCache
{
private static Northwind.SuppliersDataTable suppliers = null;
public static void LoadStaticCache()
{
// Get suppliers - cache using a static member variable
SuppliersBLL suppliersBLL = new SuppliersBLL();
suppliers = suppliersBLL.GetSuppliers();
}
[DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
public static Northwind.SuppliersDataTable GetSuppliers()
{
return suppliers;
}
}
Le code ci-dessus utilise une variable membre statique, suppliers
, pour contenir les résultats de la méthode de GetSuppliers()
la SuppliersBLL
classe, appelée à partir de la LoadStaticCache()
méthode . La LoadStaticCache()
méthode est destinée à être appelée au démarrage de l’application. Une fois ces données chargées au démarrage de l’application, toute page qui doit fonctionner avec les données du fournisseur peut appeler la méthode de GetSuppliers()
la StaticCache
classe. Par conséquent, l’appel à la base de données pour obtenir les fournisseurs ne se produit qu’une seule fois, au début de l’application.
Plutôt que d’utiliser une variable membre statique comme magasin de cache, nous aurions pu utiliser l’état de l’application ou le cache de données. Le code suivant montre la classe réorganisée pour utiliser l’état de l’application :
[System.ComponentModel.DataObject]
public class StaticCache
{
public static void LoadStaticCache()
{
// Get suppliers - cache using application state
SuppliersBLL suppliersBLL = new SuppliersBLL();
HttpContext.Current.Application["key"] = suppliersBLL.GetSuppliers();
}
[DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
public static Northwind.SuppliersDataTable GetSuppliers()
{
return HttpContext.Current.Application["key"] as Northwind.SuppliersDataTable;
}
}
Dans LoadStaticCache()
, les informations du fournisseur sont stockées dans la clé de variable d’application. Il est retourné en tant que type approprié (Northwind.SuppliersDataTable
) à partir de GetSuppliers()
. Bien que l’état de l’application soit accessible dans les classes code-behind de ASP.NET pages à l’aide Application["key"]
de , dans l’architecture que nous devons utiliser HttpContext.Current.Application["key"]
pour obtenir le actuel HttpContext
.
De même, le cache de données peut être utilisé comme magasin de cache, comme le montre le code suivant :
[System.ComponentModel.DataObject]
public class StaticCache
{
public static void LoadStaticCache()
{
// Get suppliers - cache using the data cache
SuppliersBLL suppliersBLL = new SuppliersBLL();
HttpRuntime.Cache.Insert(
/* key */ "key",
/* value */ suppliers,
/* dependencies */ null,
/* absoluteExpiration */ Cache.NoAbsoluteExpiration,
/* slidingExpiration */ Cache.NoSlidingExpiration,
/* priority */ CacheItemPriority.NotRemovable,
/* onRemoveCallback */ null);
}
[DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
public static Northwind.SuppliersDataTable GetSuppliers()
{
return HttpRuntime.Cache["key"] as Northwind.SuppliersDataTable;
}
}
Pour ajouter un élément au cache de données sans expiration basée sur le temps, utilisez les System.Web.Caching.Cache.NoAbsoluteExpiration
valeurs et System.Web.Caching.Cache.NoSlidingExpiration
comme paramètres d’entrée. Cette surcharge particulière de la méthode du cache de Insert
données a été sélectionnée afin que nous puissions spécifier la priorité de l’élément de cache. La priorité est utilisée pour déterminer les éléments à extraire du cache lorsque la mémoire disponible est faible. Ici, nous utilisons la priorité NotRemovable
, qui garantit que cet élément de cache ne sera pas supprimé.
Notes
Le téléchargement de ce didacticiel implémente la classe à l’aide StaticCache
de l’approche de variable membre statique. Le code pour l’état de l’application et les techniques de cache de données est disponible dans les commentaires dans le fichier de classe.
Étape 4 : Exécution du code au démarrage de l’application
Pour exécuter du code lorsqu’une application web démarre pour la première fois, nous devons créer un fichier spécial nommé Global.asax
. Ce fichier peut contenir des gestionnaires d’événements pour les événements au niveau de l’application, de la session et de la demande, et c’est ici que nous pouvons ajouter du code qui sera exécuté chaque fois que l’application démarre.
Ajoutez le Global.asax
fichier au répertoire racine de votre application web en cliquant avec le bouton droit sur le nom du projet de site web dans le Explorateur de solutions de Visual Studio, puis en choisissant Ajouter un nouvel élément. Dans la boîte de dialogue Ajouter un nouvel élément, sélectionnez le type d’élément Classe d’application globale, puis cliquez sur le bouton Ajouter.
Notes
Si vous avez déjà un Global.asax
fichier dans votre projet, le type d’élément Classe d’application globale ne sera pas répertorié dans la boîte de dialogue Ajouter un nouvel élément.
Figure 3 : Ajouter le Global.asax
fichier au répertoire racine de votre application web (cliquer pour afficher l’image en taille réelle)
Le modèle de fichier par défaut Global.asax
comprend cinq méthodes dans une balise côté <script>
serveur :
Application_Start
s’exécute lorsque l’application web démarre pour la première foisApplication_End
s’exécute lorsque l’application s’arrêteApplication_Error
s’exécute chaque fois qu’une exception non gérée atteint l’applicationSession_Start
s’exécute lorsqu’une session est crééeSession_End
s’exécute lorsqu’une session a expiré ou est abandonnée
Le Application_Start
gestionnaire d’événements n’est appelé qu’une seule fois pendant le cycle de vie d’une application. L’application démarre la première fois qu’une ressource ASP.NET est demandée à l’application et continue à s’exécuter jusqu’à ce que l’application soit redémarrée, ce qui peut se produire en modifiant le contenu du /Bin
dossier, en modifiant Global.asax
, en modifiant le contenu du dossier ou en App_Code
modifiant le Web.config
fichier, entre autres causes. Reportez-vous à ASP.NET Vue d’ensemble du cycle de vie des applications pour obtenir une discussion plus détaillée sur le cycle de vie de l’application.
Pour ces tutoriels, nous devons uniquement ajouter du code à la Application_Start
méthode. N’hésitez donc pas à supprimer les autres. Dans Application_Start
, appelez simplement la méthode de LoadStaticCache()
la StaticCache
classe, qui charge et met en cache les informations du fournisseur :
<%@ Application Language="C#" %>
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
StaticCache.LoadStaticCache();
}
</script>
C’est tout ! Au démarrage de l’application, la LoadStaticCache()
méthode récupère les informations du fournisseur à partir de la BLL et les stocke dans une variable membre statique (ou tout magasin de cache que vous avez fini par utiliser dans la StaticCache
classe ). Pour vérifier ce comportement, définissez un point d’arrêt dans la Application_Start
méthode et exécutez votre application. Notez que le point d’arrêt est atteint au démarrage de l’application. Toutefois, les requêtes suivantes n’entraînent pas l’exécution de la Application_Start
méthode.
Figure 4 : Utiliser un point d’arrêt pour vérifier que le Application_Start
gestionnaire d’événements est en cours d’exécution (cliquez pour afficher l’image en taille réelle)
Notes
Si vous n’atteignez pas le point d’arrêt lorsque vous démarrez le Application_Start
débogage pour la première fois, c’est que votre application a déjà démarré. Forcez l’application à redémarrer en modifiant vos Global.asax
fichiers ou Web.config
, puis réessayez. Vous pouvez simplement ajouter (ou supprimer) une ligne vide à la fin de l’un de ces fichiers pour redémarrer rapidement l’application.
Étape 5 : Affichage des données mises en cache
À ce stade, la StaticCache
classe dispose d’une version des données du fournisseur mises en cache au démarrage de l’application, accessible via sa GetSuppliers()
méthode. Pour utiliser ces données à partir de la couche de présentation, nous pouvons utiliser un ObjetDataSource ou appeler par programmation la méthode de GetSuppliers()
la StaticCache
classe à partir d’une classe code-behind d’une page ASP.NET. Examinons l’utilisation des contrôles ObjectDataSource et GridView pour afficher les informations du fournisseur mises en cache.
Commencez par ouvrir la AtApplicationStartup.aspx
page dans le Caching
dossier . Faites glisser un GridView de la boîte à outils vers le concepteur, en affectant à sa ID
propriété la valeur Suppliers
. Ensuite, à partir de la balise active de GridView, choisissez de créer un objet ObjectDataSource nommé SuppliersCachedDataSource
. Configurez ObjectDataSource pour utiliser la méthode de la StaticCache
GetSuppliers()
classe .
Figure 5 : Configurer ObjectDataSource pour utiliser la StaticCache
classe (cliquer pour afficher l’image en taille réelle)
Figure 6 : Utiliser la GetSuppliers()
méthode pour récupérer les données du fournisseur mis en cache (cliquer pour afficher l’image en taille réelle)
Une fois l’Assistant terminé, Visual Studio ajoute automatiquement BoundFields pour chacun des champs de données dans SuppliersDataTable
. Le balisage déclaratif de votre GridView et ObjectDataSource doit ressembler à ce qui suit :
<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
DataKeyNames="SupplierID" DataSourceID="SuppliersCachedDataSource"
EnableViewState="False">
<Columns>
<asp:BoundField DataField="SupplierID" HeaderText="SupplierID"
InsertVisible="False" ReadOnly="True"
SortExpression="SupplierID" />
<asp:BoundField DataField="CompanyName" HeaderText="CompanyName"
SortExpression="CompanyName" />
<asp:BoundField DataField="Address" HeaderText="Address"
SortExpression="Address" />
<asp:BoundField DataField="City" HeaderText="City"
SortExpression="City" />
<asp:BoundField DataField="Country" HeaderText="Country"
SortExpression="Country" />
<asp:BoundField DataField="Phone" HeaderText="Phone"
SortExpression="Phone" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersCachedDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetSuppliers" TypeName="StaticCache" />
La figure 7 montre la page lorsqu’elle est consultée via un navigateur. La sortie est la même si nous avons extrait les données de la classe BLL, mais l’utilisation de SuppliersBLL
la StaticCache
classe retourne les données du fournisseur telles qu’elles sont mises en cache au démarrage de l’application. Vous pouvez définir des points d’arrêt dans la méthode de GetSuppliers()
la StaticCache
classe pour vérifier ce comportement.
Figure 7 : Les données du fournisseur mises en cache sont affichées dans un GridView (cliquer pour afficher l’image en taille réelle)
Résumé
La plupart des modèles de données contiennent une quantité de données statiques, généralement implémentées sous la forme de tables de choix. Étant donné que ces informations sont statiques, il n’y a aucune raison d’accéder en permanence à la base de données chaque fois que ces informations doivent être affichées. En outre, en raison de leur nature statique, lors de la mise en cache des données, il n’est pas nécessaire d’expirer. Dans ce tutoriel, nous avons vu comment prendre ces données et les mettre en cache dans le cache de données, l’état de l’application et via une variable membre statique. Ces informations sont mises en cache au démarrage de l’application et restent dans le cache pendant toute la durée de vie de l’application.
Dans ce tutoriel et les deux derniers, nous avons examiné la mise en cache des données pour la durée de vie de l’application, ainsi que l’utilisation d’expirations basées sur le temps. Toutefois, lors de la mise en cache des données de base de données, une expiration basée sur le temps peut être inférieure à l’idéal. Plutôt que de vider régulièrement le cache, il serait préférable de supprimer l’élément mis en cache uniquement lorsque les données de base de données sous-jacentes sont modifiées. Cet idéal est possible grâce à l’utilisation des dépendances de cache SQL, que nous examinerons dans notre prochain tutoriel.
Bonne programmation !
À propos de l’auteur
Scott Mitchell, auteur de sept livres ASP/ASP.NET et fondateur de 4GuysFromRolla.com, travaille avec les technologies Web Microsoft depuis 1998. Scott travaille comme consultant indépendant, formateur et écrivain. Son dernier livre est Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Il est accessible à l’adressemitchell@4GuysFromRolla.com . ou via son blog, qui se trouve à l’adresse http://ScottOnWriting.NET.
Remerciements spéciaux à
Cette série de tutoriels a été examinée par de nombreux réviseurs utiles. Les réviseurs principaux de ce tutoriel étaient Teresa Murphy et Zack Jones. Vous souhaitez consulter mes prochains articles MSDN ? Si c’est le cas, déposez-moi une ligne à mitchell@4GuysFromRolla.com.