Dynamic Expression personnalise : ProfileExpressionBuilder avec ASP.net 2.0
Avec ASP.net 2.0 il est possible de faire d'utiliser des "Dynamic expressions" dans les pages .aspx. Qu'est-ce que c'est ? Voyons un exemple :
<asp:label runat="server" id="lbl1" text="<%$ AppSettings:MyKey %>" />
Découverte des $-expressions
Avec ASP.net 2.0 vous pouvez directement accédez aux valeurs AppSettings en utilisant la syntaxe <%$ AppSettings : keyName %>, les dynamics expressions, que j'appellerais $-expressions, est l'utilisation de la syntaxe <%$. Par défaut il existe 3 $-expressions :
Syntax |
Description |
AppSettings:[Attribute] |
Returns the value of the specified setting from the <appSettings> section of the configuration file. |
ConnectionStrings:[Entry],[Attribute] |
Returns the value of the specified attribute of the given entry in the <connectionStrings> section of the configuration file |
Resources:[ResourceFile],[ResourceName] |
Returns the value of the specified global resource. |
Ce qui est intéressant c'est qu'on peut créer nos propres $-expression. En guise d'exemple faisons un $-expression permettant de récupérer les valeurs du profile.
Création d'un $-expression personnalisé : ProfileExpressionBuilder
Explication du principe général
Tout d'abord nous devons créer une classe qui hérite de ExpressionBuilder :
[ExpressionPrefix("Profile")]
public class ProfileExpressionBuilder : ExpressionBuilder
{
public override object ParseExpression(string expression, Type propertyType, ExpressionBuilderContext context)
{
/// ...
}
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
// ...
}
}
On voit que l'on a décoré notre classe de l'attribut ExpressionPrefix, cet attribut est optionnel mais vous permet de savoir sur quelle $-expression l'ExpressionBuilder travail. On verra plus tard qu'on associe le $-expression avec l'ExpressionBuilder dans le web.config.
Ensuite on a une méthode ParseExpression qui prend en paramètre :
- un string qui contiendra dans notre exemple le nom de la propriété du profile, ce string contient tous ce qui suit le <%$ prefix: expression %>
- le type de la propriété sur laquelle est associé notre $-expression. En fait un $-expression peut être utilisé seulement pour renseigner des propriétés de contrôles serveurs, si vous mettez <%$ Profile:City %> au millieu de la page cela ne fonctionnera pas, il faut obligatoirement qu'il assigne une propriété d'un contrôle runat="server" c'est à dire <prefix:controlName runat="server" prop="<%$ Profile:City %>" />. On verra plus tard pourquoi lorsque j'expliquerais le fonctionnement des $-expressions.
- Le contexte qui permet de récupérer le nom de la page sur laquelle on utilise notre $-expression.
Le résultat de cette méthode est ensuite passé à la méthode GetCodeExpression qui elle prend en paramètre :
- les informations du contrôle sur lequel est utilisé ce $-expression.
- L'object retourné par la méthode ParseExpression
- Le context.
Le résultat de cette méthode doit être une expressionCodeDom, c'est à dire qu'à partir de cet objet, ASP.net doit être capable de générer du code qui permet de récupérer la propriété voulue du Profile.
Un peu de code
Maintenant que l'on a vu rapidement comment cela fonctionne, écrivons un peu de code :-) Dans notre cas la méthode ParseExpression devra retourner seulement le nom de la propriété du profile voulue, il suffit alors de faire :
public override object ParseExpression(string expression, Type propertyType, ExpressionBuilderContext context)
{
return expression;
}
La méthode GetCodeExpression devra elle retourner un noeud CodeDom permettant de générer :
System.Web.HttpContext.Current.Profile.GetPropertyValue(propertyName);
Mais dans la plupart des cas on génère un appel vers une méthode static car on a souvent plus d'une ligne de code à générer. Rajoutons alors une méthode static GetProperty qui retournera la valeur du profile voulue.
public static Object GetProperty(String propertyName)
{
return HttpContext.Current.Profile.GetPropertyValue(propertyName);
}
Il nous faut maintenant écrire le code CodeDom qui va générer le code permettant d'appeler la méthode statique GetProperty :
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
String propertyName = (String)parsedData;
CodePrimitiveExpression prim = new CodePrimitiveExpression(propertyName);
CodeExpression[] args = new CodeExpression[1] { prim };
CodeTypeReferenceExpression refType = new CodeTypeReferenceExpression(base.GetType());
return new CodeMethodInvokeExpression(refType, "GetProperty", args);
}
A partir de là notre ExpressionBuilder est prêt, il ne nous reste plus qu'à l'enregistrer dans le Web.config, rien de plus simple :
<compilation>
<expressionBuilders>
<add expressionPrefix="Profile" type="ProfileExpressionBuilder"/>
</expressionBuilders>
</compilation>
Vous pouvez maintenant utiliser ce code pour afficher le contenu du profile :
<asp:Label ID="lbl1" runat="server" Text="<%$ Profile:City %>"></asp:Label>
Support des "no-compile Pages"
ASP.net 2.0 permet de ne pas compiler automatiquement certaines pages, je ne vais pas rentrer en détails dans le fonctionnement des "no-compile Pages" mais c'est possible en définissant l'attribut CompilationMode à Never (l'attribut CompilationMode sur MSDN). Bref, dans ce cas vous devez surchargé la méthode EvaluateExpression, je détail pas le code car les "no-compiles pages" sont très rarement utile. Vous devez également surcharger une propriété pour spécifier que votre $-expression est utilisable avec ce type de page :
public override object EvaluateExpression(object target, BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
return GetProperty((String)parsedData);
}
public override bool SupportsEvaluate
{
get
{
return true;
}
}
Cet exemple provient du livre "ASP.net 2.0 Applications - Advanced Topics" de Dino Esposito, vous pouvez retrouver le code complet sur aspfr.com : Accéder aux propriétés du Profile via un ExpressionBuilder personnalisé
Fonctionnement des $-expression
La majorité du code de notre ExpressionBuilder sera executé lors de la pré-compilation des pages, en effet lorsque le parseur ASP.net (ie : la classe PageBuildProvider) tombe sur une $-expression lors de la génération du code final de la page, il regarde quelle est le préfixe (AppSettings, Profile, ...) cherche l'ExpressionBuilder associé dans le web.config, appel la méthode ParseExpression puis génére le code à partir de l'expression CodeDom retourné par la méthode GetCodeExpression et enfin écrit le code dans la méthode surchargé __BuildControlTree de la Page, les $-expression sont donc appelés lors de l'appel de la méthode __BuildControlTree c'est à dire au tout début du cycle de vie de la page.
Ressource :
Il n'existe malheureusement pas beaucoup d'article parlant de la pré-compilation des pages ASP.net
Dino Esposito en parle très bien sur le bouquin "ASP.net 2.0 Applications - Advanced Topics"
Il y a heureusement la documentation la plus complete sur ASP.net : Reflector for .NET
Si vous avez des questions sur le fonctionnement des $-expression les commentaires sont là pour ça ;-)
PS : vous avez vu ? pas une ligne de JavaScript !!! ;-)