Creating a Custom ExpressionBuilder in ASP.NET 2.0
page 3 of 6
by Bilal Haidar
Feedback
Average Rating: 
Views (Total / Last 10 Days): 37868/ 81

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.


View Entire Article

User Comments

Title: Enquiry   
Name: Bharat Bhushan
Date: 2010-11-03 1:31:44 AM
Comment:
I got the use of expression prefix but i want to know
about type attributes of add tag of expressionbuilders
tag
Title: Expression Builder - Excellent!   
Name: Matt, UK
Date: 2009-10-19 5:48:20 PM
Comment:
Hi,

Fantastic article. Downloaded the sample and it works like a dream. Many thanks for this!
Title: Expression Builder   
Name: Unknown
Date: 2008-12-12 7:24:13 AM
Comment:
Really very good example with all the description in short language

Thanks a lot and It's easy to understand...
Title: Custom Expression   
Name: S.Y.
Date: 2007-09-27 4:34:17 PM
Comment:
The custom expression works great but is there a way to set this from the properties expression editor? It only accepts RESOURCES, APPSETTINGS and CONNECTIONSTRINGS. Is it possible to have the XmlSettings part of the expression type? Wanted to view the actual literal at the design time.

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2021 ASPAlliance.com  |  Page Processed at 2021-12-01 8:30:48 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search