Other Types of Expressions

Other Types of Expressions
Data binding expressions are always wrapped in the <%# and %> characters. ASP.NET 2.0 also adds
support for different types of expressions, commonly known as $ expressions because they incorporate
the $ character. Technically, a $ expression is a code sequence that you can add to an .aspx page
and that will be evaluated by an expression builder when the page is rendered. The expression
builder processes the expression and replaces it with a string value in the final HTML.
Currently, ASP.NET includes a built-in expression builder that allows you to extract custom
application settings and connection string information from the web.config file. For example, if
you want to retrieve an application setting named appName from the <appSettings> portion of the
web.config file, you can use the following expression:
<asp:Literal Runat="server" Text="<%$ AppSettings:appName %>" />
Several differences exist between $ expressions and data binding expressions:
• Data binding expressions start with the <%# character sequence, and $ expressions use <%$.
• Unlike data binding expressions, you don’t need to call the DataBind() method to evaluate $
expressions. Instead, they’re always evaluated when the page is rendered.
298 CHAPTER 9 ■ DATA BINDING
• Unlike data binding expressions, $ expressions can’t be inserted anywhere in a page. Instead,
you need to wrap them in a control tag and use the expression result to set a control property.
That means if you just want to show the result of an expression as ordinary text, you
need to wrap it in a Literal tag (as shown in the previous example). The Literal control outputs
its text to plain, unformatted HTML.
The first part of a $ expression indicates the name of the expression builder. For example, the
AppSettings:appName expression works because a dedicated AppSettingsExpression builder is
registered to handle all expressions that begin with AppSettings. Similarly, ASP.NET includes a
ResourceExpressionBuilder for inserting resources (see Chapter 17) and a ConnectionString-
ExpressionBuilder that retrieves connection information from the <connectionStrings> section
of the web.config file. Here’s an example that uses the ConnectionStringExpressionBuilder:
<asp:Literal Runat="server" Text="<%$ ConnectionStrings:Northwind %>" />
Displaying a connection string isn’t that useful. But this technique becomes much more useful
when you combine it with the SqlDataSource control you’ll examine later in this chapter, in which
case you can use it to quickly supply a connection string from the web.config file:
<asp:SqlDataSource ConnectionString="<%$ ConnectionStrings:Northwind %>" ... />
Technically, $ expressions don’t involve data binding. But they work in a similar way and have a
similar syntax.
Custom Expression Builders
One of the most innovative features of $ expressions is that you can create your own expression
builders that plug into this framework. This is a specialized technique that, while neat, isn’t always
practical. As you’ll see, custom $ expressions make the most sense if you’re developing a distinct
feature that you want to incorporate into more than one web application.
For example, imagine you want a way to create a custom expression builder that allows you to
insert random numbers. You want to be able to write a tag such as this to show a random number
between 1 and 6:
<asp:Literal Runat="server" Text="<%$ RandomNumber:1,6 %>" />
Unfortunately, creating a custom expression builder isn’t quite as easy as you probably expect.
The problem is how the code is compiled. When you compile a page that contains an expression,
the expression evaluating the code also needs to be compiled with it. However, you don’t want the
expression to be evaluated at that point—instead, you want the expression to be reevaluated each
time the page is requested. To make this possible, your expression builder needs to generate a
generic segment of code that performs the appropriate task.
The technology that enables this is CodeDOM (Code Document Object Model)—a model
for dynamically generating code constructs. Every expression builder includes a method named
GetCodeExpression() that uses CodeDOM to generate the code needed for the expression. In other
words, if you want to create a RandomNumberExpressionBuilder, you need to create a GetCode-
Expression() method that uses CodeDOM to generate a segment of code for calculating random
numbers. Clearly, it’s not that straightforward—and for anything but trivial code, it’s quite lengthy.
All expression builders must derive from the base ExpressionBuilder class (which is found in
the System.Web.Compilation namespace). Here’s how you might declare an expression builder for
random number generation:
public class RandomNumberExpressionBuilder : ExpressionBuilder
{ ... }
CHAPTER 9 ■ DATA BINDING 299
To simplify life, it helps to create a static method that performs the task you need (in this case,
random number generation):
public static string GetRandomNumber(int lowerLimit, int upperLimit)
{
Random rand = new Random();
int randValue = rand.Next(lowerLimit, upperLimit + 1);
return randValue.ToString();
}
The advantage of this approach is that when you use CodeDOM, you simply generate the
single line of code needed to call the GetRandomNumber() method (rather than the code needed
to generate the random number).
Now, you need to override the GetCodeExpression() method. This is the method that ASP.NET
calls when it finds an expression that’s mapped to your expression builder (while compiling the
page). At this point, you need to examine the expression, verify no errors are present, and then
generate the code for calculating the expression result (using a CodeExpression object from the
System.CodeDom namespace). This dynamically generated piece of code will be executed every
time the page is requested.
Here’s the first part of the GetCodeExpression() method:
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry,
object parsedData, ExpressionBuilderContext context)
{
// entry.Expression is the number string
// without the prefix (for example "1,6").
if (!entry.Expression.Contains(","))
{
throw new ArgumentException(
"Must include two numbers separated by a comma.");
}
else
{
// Get the two numbers.
string[] numbers = entry.Expression.Split(',');
if (numbers.Length != 2)
{
throw new ArgumentException("Only include two numbers.");
}
else
{
int lowerLimit, upperLimit;
if (Int32.TryParse(numbers[0], out lowerLimit) &&
Int32.TryParse(numbers[1], out upperLimit))
{
...
So far, all the operations have been performed in normal code. That’s because the two numbers
are specified in the expression, so they won’t change each time the page is requested. However, the
random number should be allowed to change each time, so now you need to switch to CodeDOM to
create a dynamic segment of code. The basic strategy is to construct a CodeExpression that calls the
static GetRandomNumber() method.
300 CHAPTER 9 ■ DATA BINDING
Here’s the rest of the code:
...
// Specify the class.
Type type = entry.DeclaringType;
PropertyDescriptor descriptor =
TypeDescriptor.GetProperties(type)[entry.PropertyInfo.Name];
// Define the parameters.
CodeExpression[] expressionArray = new CodeExpression[2];
expressionArray[0] = new CodePrimitiveExpression(lowerLimit);
expressionArray[1] = new CodePrimitiveExpression(upperLimit);
// Define the expression that invokes the method.
return new CodeCastExpression(descriptor.PropertyType,
new CodeMethodInvokeExpression(
new CodeTypeReferenceExpression(base.GetType()),
"GetRandomNumber", expressionArray));
}
else
{
throw new ArgumentException("Use valid integers.");
}
}
}
}
Now you can copy this expression builder to the App_Code folder (or compile it separately and
place the DLL assembly in the Bin folder).
Finally, to use this expression builder in a web application, you need to register it in the
web.config file and map it to the prefix you want to use:
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.web>
<compilation debug="true">
<expressionBuilders>
<add expressionPrefix="RandomNumber"
type="RandomNumberExpressionBuilder"/>
</expressionBuilders>
</compilation>
...
</system.web>
</configuration>
Now you can use expressions such as <%$ RandomNumber:1,6 %>. These expressions are
automatically handled by your custom expression builder, which generates a new random number
in the desired range each time the page runs.
The possibilities for expression builders are intriguing. They enable many extensibility scenarios,
and third-party tools are sure to take advantage of this feature. However, if you intend to use
an expression in a single web application or in a single web page, you’ll find it easier to just use a
data binding expression that calls a custom method in your page. For example, you could create
a data binding expression like this:
<%# GetRandomNumber(1,6) %>
CHAPTER 9 ■ DATA BINDING 301
And add a matching public or protected method in your page, like this:
protected string GetRandomNumber(int lowerLimit, int upperLimit)
{ ... }
Just remember to call Page.DataBind() to evaluate your expression.
posted @ 2008-04-04 00:03  陋室  阅读(326)  评论(0编辑  收藏  举报