AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=1113&pId=-1
Creating a Custom ExpressionBuilder in ASP.NET 2.0
page
by Bilal Haidar
Feedback
Average Rating: 
Views (Total / Last 10 Days): 35370/ 46

Introduction

A new feature in ASP.NET 2.0 has been introduced, the ExpressionBuilder. The ExpressionBuilder allows declarative binding for control properties for data that is coming either from the ConnectionStrings and AppSettings section of the web configuration file or from the web application resource files.

The way you add a declarative expression to a control property is as follows:

Listing 1

<asp:Label ID="lblPath" runat="server" Text='<%$ AppSettings: WebPath %>' />

As you can see above, we have assigned the Text property of the Label control a declarative expression which shall retrieve the WebPath key from the AppSettings section of the web.config file of the ASP.NET web application.

When the page is being parsed, if the parser passes by such a declarative expression, it will create a new instance of the AppSettingsExpressionBiulder and then evaluate the expression. Evaluating the expression in this case is by taking the right hand side of the declarative expression which is WebPath and then retrieving the value of that key from the web configuration file. Finally, it binds the value of that key to the Text property of the Label control.

In this article we will cover the different built-in ExpressionBuilders that shipp with the ASP.NET 2.0 and build a custom ExpressionBuilder to bind the ASP.NET controls to a separate XML settings files.

Built-in ExpressionBuilders

ASP.NET 2.0 ships with three ExpressionBuilders:

AppSettingsExpressionBuilder: Used to retrieve values from the AppSettings section of the web configuration file.

ConnectionStringsExpressionBuilder: Used to retrieve values from the ConnectionStrings section of the web configuration file.

ResourceExpressionBuilder: Used to retrieve values from the resource files, whether Local or Global resources.

AppSettingsExpressionBiulder

The .NET Framework creates a new instance of the AppSettingsExpressionBuilder when you are using a declarative expression that is accessing a key from the AppSettings section of the web configuration file.

The example clarifies how to access the AppSettings section declaratively.

Listing 2

<asp:Label ID="lblPath" runat="server" Text='<%$ AppSettings: WebPath %>' />

As explained above, the code is retrieving the WebPath key from the AppSettings section and binding it to the Text property of the Label server control.

ConnectionStringsExpressionBuilder

Most of you have seen such a code:

Listing 3

<asp:SqlDataSource ID="SqlDataSource1"
 runat="server" ConnectionString="<%$ ConnectionStrings:MyConnectionString %>" 
SelectCommand="SELECT * FROM [CMS_ACL]"></asp:SqlDataSource>

This is a SqlDataSource control that handles the connection with a database and retrieves data according to the SelectCommand. You can see the existence of the ConnectionString property that has been assigned a declarative expression to retrieve the connection string from the ConnectionStrings section of the web configuration file.

ResourceExpressionBuilder

ASP.NET 2.0 made building Multilanguage web applications an easy task to do when they introduced the App_LocalResources and App_GlobalResources special folders to hold the local and global resource files respectively. Accessing both Global and Local resources can be done through the explicit declarative expression by specifying the Resources keyword on the left hand side of the declarative expression.

We have created a local resource file called Default.aspx.resx placed in the App_LocalResources folder. In a web form named Default.aspx we have placed the following Label server control.

Listing 4

<asp:Label ID="lblResourceKey" runat="server" Text="<%$ Resources:KeyFromResource %>" />

As you can see, the keyword Resources have been used on the left hand side of the expression and on the right hand side the key name to retrieve its values has been specified.

Custom Expression Builder

In this section of the article we will develop a custom ExpressionBuilder. This expression builder will be used to retrieve values based on a key from an XML settings file. Sometimes it seems proper to store some configuration settings for a web application in a separate XML file for several reasons, among which is to change the XML settings file without requiring the .NET Framework to recompile the whole application.

The ExpressionBuilder class is an abstract class where all the above expression builders extend from. This abstract class contains one method that should be overridden by any class extending it and this is the GetCodeExpression. The GetCodeExpression returns the expression to be executed to obtain the evaluated expression when the Page parser finds a declarative expression and calls the required ExpressionBuilder. This method returns an expression of type CodeExpression and part of the CODEDom. The reason behind using the CodeDom is that, during the Page parsing, when a declarative expression is found, the corresponding ExpressionBuilder executes the GetCodeExpression and the return value is just a CodeExpression that will be embedded into the compiled ASP.NET class and then all together compiled and executed. The resulting class is stored in the ASP.NET Temporary folder. Since the ExpressionBuilder might be used in an ASP.NET web application that is either built using Visual Basic .NET or C#, the GetCodeExpression must be language neutral and the CodeDom must be integrated with any language set for the web application.

The GetCodeExpression has a major parameter that you will be using caled entry. This object represents the property that the current expression is bound to. For example, look at the following declarative expression.

Listing 5

<asp:Label ID="lblPath" runat="server" Text='<%$ AppSettings: WebPath %>' />

The entry parameter is Text property of the Label server control.

In addition, if you want your declarative expressions to be evaluated with no-compile pages, you should override the EvaluateExpression method and the SupportsEvaluate property so that the expressions will be evaluated even before compiling your web applications. More on those methods and properties will be shown in the section below where we create the custom XMLSettingExpressionBuilder.

XML Settings file

The ExpressionBuilder that we will develop will interact with an XML file. The XML file has the following structure.

Listing 6

<?xml version="1.0"?>
<xmlsettings>
  <add key="WebPath" value="http://www.mywebsite.com" />
</xmlsettings >

The expression builder shall be able to retrieve values from the above XML settings file by using the key values as a look up key for each of the configurations listed in this file.

XMLSettingExpressionBuilder

As mentioned above, to develop a new ExpressionBuilder we should extend the ExpressionBuilder abstract class and override the major method which is the GetCodeExpression.

The header of the XmlSettingExpressionBuilder is as follows.

Listing 7

public class XmlSettingExpressionBuilder : ExpressionBuilder
{

The GetCodeExpression is a method that will be called during the page execution to get the expression that is going to be executed when it is time to bind the declarative expression on the page.

Listing 8

public override CodeExpression GetCodeExpression(BoundPropertyEntry entry,
  object parsedData, ExpressionBuilderContext context)
{
  CodeTypeReferenceExpression thisType = new CodeTypeReferenceExpression
    (base.GetType());
  CodePrimitiveExpression expression = new CodePrimitiveExpression
    (entry.Expression.Trim().ToString());
  string evaluationMethod = "GetXmlSetting";
  return new CodeMethodInvokeExpression(thisType, evaluationMethod, new
    CodeExpression[]
  {
    expression
  }
  );
}

The first line of this method gets a reference to the XmlSettingExpressionBuilder class because we are going to execute a method on this class that will evaluate the required expression.

Then, it creates a new expression based on the KEY specified in the declarative expression on the page which will be used as an input to the method that will evaluate the required expression.

A method name that will do the real evaluation is stored in a string variable. Finally, the method returns the expression that will invoke a method named GetXmlSetting, which is a static method responsible for evaluating the expression. The CodeMethodInvokeExpression class has been used for this purpose and takes as input the type on which to execute the method specified the method name, as well as an array of type CodeExpression that represents the parameters of the method called.

As a summary, the GetCodeExpression returns a CodeDOM method invocation expression so that this method invocation will be added to the page compiled class and executed later on when the whole page executes.

We have mentioned the method GetXmlSetting which is responsible for loading the data based on the key specified in the declarative expression. The implementation of that method is as follows.

Listing 9

public static string GetXmlSetting(string expression)
{
  XmlDocument xmlSettingDoc = (XmlDocument)HostingEnvironment.Cache[
    "XmlSettings"];
 
  if (xmlSettingDoc == null)
  {
    xmlSettingDoc = new XmlDocument();
    string settingsFile = HostingEnvironment.MapPath("~/XmlSettings.config");
    xmlSettingDoc.Load(settingsFile);
    CacheDependency settingsDepend = new CacheDependency(settingsFile);
    HostingEnvironment.Cache.Insert("XmlSettings", xmlSettingDoc,
      settingsDepend);
  }
 
  string getXPATHKey = String.Format("//add[@key='{0}']", expression);
  XmlNode wantedRecord = xmlSettingDoc.SelectSingleNode(getXPATHKey);
  if (wantedRecord != null)
    return wantedRecord.Attributes["value"].Value;
 
  return "Unable to Process Expression";
}

The GetXmlSetting method evaluates the declarative expression by accessing the XMLSettings.config file and retrieving the value corresponding to the key specified in the above mentioned expression.

The method simply loads the XmlSettings.config file into an XmlDocument. If this file has been loaded before, it is checking if it is still placed in the application cache. If not, it loads the file into the XmlDocument then adds it to the application cache to gain some performance points by caching the file content.

An XPATH expression is built based on the add record whose key attribute value is the same as the one specified in the declarative expression. Finally, the value attribute value is returned as if we had a lookup based on the key attribute. If there was no such key, we could have simply thrown an exception, but in this case we simply returned a warning message that the expression could not be evaluated properly.

Now the picture is clear. The GetCodeExpression returns a CodeDOM expression that invokes the method GetXmlSetting. When the page executes, it finds a call to the GetXmlSetting, it invokes this method and the returned value replaces the declarative expression on the page.

In addition, if you wanted to enable the Expression Builder in no-compile pages, another method should be overriden together with a public property.

Listing 10

public override object EvaluateExpression(object target, BoundPropertyEntry
  entry, object parsedData, ExpressionBuilderContext context)
{
// Call the GetXmlSetting method --> evaluate the expression
  return GetXmlSetting(entry.Expression);
}
 
public override bool SupportsEvaluate
{
  get
  {
    return true;
  }
}

The EvaulateExpression method simply returns a call to the GetXmlSetting method. The SupportsEvaluate property returns true, meaning that the ExpressionBuilder is enabled on no-compile pages.

How to use the XmlSettingExpressionBuilder

The first thing to do is to place the XmlSettingExpressionBuilder class in the App_Code folder. Next, add the following section to the web configuration file under the compilation section.

Listing 11

<compilation debug="true">
  <expressionBuilders>
   <add expressionPrefix="XmlSettings"
   type="BilalHaidarLibrary.XmlSettingExpressionBuilder"/>
  </expressionBuilders>
</compilation>  

We have registered the new ExpressionBuilder in the web configuration file and now the web application is ready to use it.

On a new WebForm you simply add the following server control.

Listing 12

<asp:literal ID="expressionTest" runat="server" Text='<%$ XmlSettings: WebPath %>' />

The .NET runtime will take the XmlSettings keyword, create a new instance of the XmlSettingExpressionBuilder and evaluate the expression; in this case it is the value of the key attribute of each record in the XmlSettings.config file.

Downloads
Resources

We would recommend checking the following links to get more information on the CodeDOM which is basically used in creating the ExpressionBuilder.

Microsoft .NET CodeDom Technology - Part 1

Microsoft .NET CodeDom Technology - Part 2

Using the CodeDOM

Generate .NET Code in Any Language Using CodeDOM

Conclusion

We have explained what the ExpressionBuilder is, detailed the different ExpressionBuilders that are built-in in the .NET Framework, and developed a custom ExpressionBuilder, the XmlSettingExpressionBuilder whose implementation was fully covered with detailed explanation.


Product Spotlight
Product Spotlight 

©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-03-29 4:07:20 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search