En ASP.NET, l’UpdatePanel permet d’intéragir avec le serveur sans avoir à recharcher la page (mode asynchrone).
Le code suivant affiche la date courante dans le label lors du click sur le bouton sans avoir à recharger la page :
- UpdatePanel.aspx
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Button ID="bt1" runat="server" Text="Button"
onclick="bt1_Click" />
<asp:Label ID="lbl1" runat="server" Text="Label"></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
- UpdatePanel.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class UpdatePanel : System.Web.UI.Page
{
protected void bt1_Click(object sender, EventArgs e)
{
lbl1.Text = DateTime.Now.ToString();
}
}
Ce qui donne le résultat suivant lors du click sur le bouton, le tout sans rechargement de page :
![]()
Le processus est très simple, on pourrait être tenter de mettre ce contrôle partout sur le site internet pour bénéficier de la fluidité de l’AJAX.
Si on regarde d’un peu plus près ce qu’il se passe entre le client et le serveur, on s’aperçoit que tout le view state de la page est renvoyé à chaque action dans l’UpdatePanel :
Si on multiplie ce type d’action plusieurs fois dans la page avec plusieurs contrôles (TextBox, Label, etc…), chaque échange avec le serveur peut devenir très lourd. Cette lourdeur n’empêche pas l’utilisation des UpdatePanels, il faut juste être conscient du fonctionnement de ce contrôle pour ne pas l’utiliser à outrance. Ici l’utilisation du framework ASP.NET AJAX est une très bonne alternative pour alléger les échanges.
Le projet utilisé dans cet article est disponible ici.
Info : Pour obtenir des informations concernant les échanges entre le client et le serveur, utilisez Firefox avec le module Firebug.
Un système de cache permet de mettre temporairement des données en mémoire sur le serveur permettant un affichage plus rapide des pages du site web.
En ASP.NET, il existe plusieurs solutions pour créer un système de cache :
Dans cet article, c’est une partie du Data Caching qui nous intéresse : le SQL Server Cache Dependency. Le principe de cette méthode de caching est de limiter les appels à la base de données en mettant en cache le résultat d’une requête SQL et en l’utilisant tant que la table à qui elle fait appel n’est pas modifiée.
Concrètement si un GridView utilise un SqlDataSource pour récupérer toutes les colonnes de la table MaTable dans une base de données.
Comment mettre en place le SQL Server Cache Dependency
Attention, la mise en place décrite ci-dessous ne fonctionne que sur SQL Server 2005 et plus. Pour SQL Server 2000 le SQL Cache Dependency est possible, mais beaucoup plus lourd à mettre en place.
Premièrement, pour activer les notifications sur SQL Server (qui permettront d’avertir du changement dans une table), démarrer Visual Studio Command Prompt (Démarrer -> Tous les programmes -> Microsoft Visual Studio 2010 -> Visual Studio Tools -> Visual Studio Command Prompt).
Tapez ensuite : SqlCmd -S <Serveur_de_base_de_données>
Entrez ensuite les requêtes suivantes :
USE <Base_de_données> ALTER DATABASE <Base_de_données> SET ENABLE BROKER GO
Attention, pour que cette requête s’exécute avec succès, aucune autre session ne doit être ouverte pour cette base de données.
Il faut ensuite ajouter une entrée dans le web.config pour indiquer que la base de données utilisera le cache :
<system.web>
<caching>
<sqlCacheDependency enabled="true">
<databases>
<add name="Ma_Base" connectionStringName="Site" pollTime="20000"/>
</databases>
</sqlCacheDependency>
</caching>
</system.web>
Il faut ensuite activer les notifications pour la base de données et pour la table concernée. Pour pouvoir accéder à la classe SqlCacheDependencyAdmin, importez System.Web.Caching dans votre page.
string cnx = ConfigurationManager.ConnectionStrings["Site"].ToString();
SqlCacheDependencyAdmin.EnableNotifications(cnx);
SqlCacheDependencyAdmin.EnableTableForNotifications(cnx, "Ma_Table");
Dernière étape, activer le Cache dans les propriétés du SqlDataSource ou ObjectDataSource.
EnableCaching doit être passé à true et SqlCacheDependency doit contenir MaBase:MaTable.
Il faut noter qu’une table AspNet_SqlCacheTablesForChangeNotification est créée pour stocker les changements dans la base de données. A chaque modification le champ changeId est incrémenté de 1.
Les performances
Pour démontrer les performances de ce système de cache, j’ai fait des tests sur une requête SQL qui récupère les 34487 villes de France. Le test se base sur 10 exécutions de page dans les 2 cas et avec une désactivation du cache du navigateur.
Sans cache, l’exécution moyenne des pages est de 0,4825s alors qu’avec le cache, on obtient une exécution moyenne de 0,0284s soit une exécution 17 fois inférieure.
Il est possible de télécharger ici le projet utilisé pour les tests.
Avec l’utilisation du système intégré à ASP.NET pour gérer les utilisateurs, il peut être utile de récupérer l’identifiant de l’utilisateur actuellement connecté par exemple pour récupérer des données dans une base qui se rapporte à cet utilisateur.
Voici le code qui permet de récupérer l’UserId :
string userID = Membership.GetUser().ProviderUserKey.ToString();
Dans un article précédent, j’expliquais comment envoyer un email en C#, un autre aspect intéressant de l’envoi de mail est de pouvoir utiliser un fichier texte comme template. Cette fonctionnalité est utilisée notamment par le contrôle CreateUserWizard avec le MailDefinition :
<MailDefinition BodyFileName="~/Skels/template.txt"
Subject="Sujet du mail">
</MailDefinition>
Le code ci-dessus permet donc d’utiliser le contenu du fichier template.txt comme corps de notre email.
Pour reproduire ce comportenant en C#, il faut utiliser la classe MailDefinition comme exposé dans l’exemple suivant.
Namespaces :
using System; using System.Net.Mail; using System.Collections.Generic; using System.Web.UI.WebControls;
Code C# :
MailDefinition def = new MailDefinition();
def.BodyFileName = "/template.txt";
Dictionary<string, string> data = new Dictionary<string, string>();
data.Add("var1", "Contenu de ma variable 1");
data.Add("var2", "Contenu de ma variable 2");
MailMessage email = def.CreateMailMessage("aymeric.lagier@gmail.com", data, this);
email.From = new MailAddress("no-reply@aymericlagier.com");
email.Subject = "Sujet de mon mail";
SmtpClient client = new SmtpClient();
client.Send(email);
Contenu de template.txt :
ma var 1 : var1 ma var 2 : var2
Résultat :
Lorsque l’on veut utiliser un GridView pour ajouter/modifier/supprimer des données dans une table SQL qui a pour clé primaire un Guid (par exemple aspnet_Users), une erreur survient lorsque l’on veut modifier ou supprimer un élément :
Could not find a property named ‘xxx’ on the type specified by the DataObjectTypeName property in ObjectDataSource ‘yyy’
Tout semble pourtant bien configurer, mais l’erreur persiste. J’ai été confronté à ce problème avec la table aspnet_Users, qui contient les utilisateurs créés avec le système interne d’ASP.NET.
Voici ma solution au problème, je ne garantis pas qu’elle soit optimale. Elle se base sur la table aspnet_Users
Après plusieurs recherches sur Google, j’ai trouvé la solution suivante : Supprimer le contenu de l’attribut DataObjectTypeName qui contient normalement System.Guid.
Chez moi cette solution ne fonctionne pas.
La solution que je vous propose est de convertir ce Guid en nvarchar lors de la récupération de nos données. Ce nvarchar sera ensuite passer en argument des méthodes Update et Delete. Concrétement la requête de récupération des données sera de ce type :
SELECT u.UserId, CAST(u.UserId AS nvarchar(MAX)) AS UserIdStr, u.UserName FROM aspnet_Users u
Du côté ASPX, il faut mettre UserIdStr comme valeur de la propriété DataKeyNames et rendre les colonnes UserIdStr et UserId non visible et en readonly. Le code du GridView ressemble à ceci :
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="ObjectDataSource1" DataKeyNames="UserIdStr">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:BoundField DataField="UserId" HeaderText="UserId"
SortExpression="UserId" Visible="false" ReadOnly="true" />
<asp:BoundField DataField="UserName" HeaderText="UserName"
SortExpression="UserName" />
<asp:BoundField DataField="Email" HeaderText="Email" SortExpression="Email" />
<asp:CheckBoxField DataField="IsApproved" HeaderText="IsApproved"
SortExpression="IsApproved" />
<asp:BoundField DataField="UserIdStr" HeaderText="UserIdStr"
SortExpression="UserIdStr" Visible="false" ReadOnly="true" />
</Columns>
</asp:GridView>
Et l’ObjectDataSource ressemble à ceci :
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
DeleteMethod="Delete" SelectMethod="FetchAll"
TypeName="Project.Business.BLLUsers" UpdateMethod="Update">
<DeleteParameters>
<asp:Parameter Name="UserIdStr" Type="String" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="UserIDStr" Type="String" />
<asp:Parameter Name="Username" Type="String" />
<asp:Parameter Name="Email" Type="String" />
<asp:Parameter Name="IsApproved" Type="Boolean" />
</UpdateParameters>
</asp:ObjectDataSource>
Dans mon cas, les méthodes Update et Delete appellent des procédures stockées qui prennent pour identifiant un paramètre de type nvarchar(MAX).
Si vous trouvez une autre méthode pour arriver au même résultat, faites moi signe
.