Using Expression Builders in ASP.NET
By Scott Mitchell
Introduction
ASP.NET offers a variety of ways to inject the results of a server-side expression (such as
DateTime.Now.ToString()
) into the rendered markup of an ASP.NET page.
The most common way is to add a Label Web control to the page and then from the Page_Load
event handler (or some other suitable event handler) assign the value
to display to the Label's Text
property. If you ever created web applications using ASP.NET's predecessor, classic ASP, or if you are familiar with
Microsoft's ASP.NET MVC, then you know that another way to inject server-side information is to add
<%= expression %>
to the declarative content like so:
The current time is: <%= DateTime.Now.ToString() %>
|
The <%= expression %>
syntax is translated into Response.Write(expression)
, injecting the value of expression into the
page's rendered output. Because <%= expression %>
is translated into (essentially) a Response.Write
these statements cannot be used to set the values
of Web control properties. In other words, you cannot have markup like the following:
<asp:Label runat="server" id="CurrentTime" Text="<%= DateTime.Now.ToString() %>" />
|
An alternate way to display server-side information is to assign it to a Web control property directly from the declarative markup using an expression builder. An
expression builder is denoted using the syntax <%$ expression %>
(note the $
after <%
).
The expression cannot be an arbitrary snippet of code as with <%= ... %>
, but instead is limited to what expression builders the website is configured
to use. Moreover, expression builders must be assigned to a Web control property; they cannot appear in any which place in the declarative markup like <%= expression %>
.
ASP.NET ships with three built-in expression builder classes that let you declaratively access the values in the configuration's AppSettings
collection, the
ConnectionStrings
collection, and in the website's resources (typically defined in the App_LocalResources
and App_GlobalResources
folders).
With a little bit of code you can create your own expression builders. This article provides an overview of how expression builders work and shows how to create your
own expression builders. Read on to learn more!
A Primer on How Declarative Markup Is Translated Into Code
When an ASP.NET page is visited the declarative markup in the page is converted into source code and compiled into an assembly that derives from the page's code-behind class. In short, this step turns the declarative markup - the static HTML content and Web control markup - into a C# or Visual Basic class file. This auto-generated class's primary responsibility is to create the page's control hierarchy, which involves creating
LiteralControl
s for each block of static HTML, creating objects that
represent each Web control on the page, and adding these controls to the Page
object's Controls
collection. You can find these auto-generated classes
in the %WINDOWS%\Microsoft.NET\Framework\version\Temporary ASP.NET Files
folder.
Consider the following simple page, which has a Web Form (<form runat="server">
), inside which there is a mix of static HTML and Web controls, namely
a TextBox, Button, and Label.
<html xmlns="http://www.w3.org/1999/xhtml" >
|
When this page is visited for the first time (or for the first time after the page's content has changed) the declarative markup is transformed into a class file that constructs
the page's control hierarchy based on the contents in the declarative markup. The control hierarchy construction is kick started by the auto-generated class's
FrameworkInitialize
method, which contains a call to a method named BuildControlTree
. @__BuildControlTree
is where the magic happens.
@__BuildControlTree
starts by creating a LiteralControl
that contains the static HTML markup at the start of the document (<html>
,
<head>
, <body>
, etc.). Next, it generates the control hierarchy for the Web Form. It completes by creating a LiteralControl
that contains the static HTML markup at the end of the document (</body>
, </html>
, etc.).
private void @__BuildControlTree(codedemo_aspx @__ctrl) {
|
The @__BuildControlform1
method creates the control hierarchy for the Web Form, creating and adding Web control objects for each Web control defined in the Web
Form. This method also sets the properties for the Web Form that are defined in the declarative markup (the ID
, for instance).
private global::System.Web.UI.HtmlControls.HtmlForm @__BuildControlform1() {
|
The methods that create the corresponding Web control objects follow a similar pattern: they create the Web control in question and set those properties that were defined
in the declarative markup. If the Web control has children controls, the logic recurses into additional method calls to add those children Web controls. Here's the
code for the @__BuildControlbtnSubmit
, which generates the object and sets the properties for the Button Web control.
As you can see, those Button properties defined explicitly in the markup - ID
and Text
- are assigned to "btnSubmit" and "Click Me!", respectively.
private global::System.Web.UI.WebControls.Button @__BuildControlbtnSubmit() {
|
As I noted in the introduction, one way to inject server-side information into the rendered markup is to use <%= expression %>
. Adding such
content writes expression directly to the output stream alongside the other literal content on the page. That is why you cannot assign a Web control value using the
<%= expression %>
syntax.
Enter Expression Builders
Starting with ASP.NET 2.0 it is possible to have more control over the value assigned to the Web controls' properties by the auto-generated class. Instead of only being able to assign a static value to a property via the declarative syntax (as in
<asp:Label ... Text="Hello!" />
),
it is possible to use an expression builder to assign the property a dynamic value. With an expression builder you use the syntax <%$ expression %>
to assign a Web control property a dynamic value (as in <asp:Label ... Text="<%$ expression %>" />
).
When the runtime converts the declarative markup to the auto-generated class file, it parses the expression builder syntax to determine what expression builder class is responsible
for generating the corresponding expression. Such a class must extend the ExpressionBuilder
class, which spells out the default functionality for expression builders. Specifically, the corresponding expression builder class's GetCodeExpression
method is called and passed information about the Web control property the expression builder is being bound to, the value of expression in the
<%$ expression %>
syntax, and other information. The expression builder class is responsible for generating a
CodeExpression
instance that will be used to assign the Web control's
property value. (The CodeExpression
class is part of the .NET Framework's CodeDom library, which allows for developers to write code that generates code.)
To better understand how expression builders work, let's review the AppSettingsExpressionBuilder
class, which is one of three expression builder classes that are built into the .NET Framework. As its name implies, the AppSettingsExpressionBuilder
class
is used to return values from the AppSettings
section defined in the application's configuration (Web.config
). For example, imagine that you have
a Web.config
file with the following <appSettings>
section:
<configuration>
|
You could use an expression builder like so to display this value in a Label control on an ASP.NET page:
<div id="footer">
|
When this page was first visited and the declarative markup converted into an auto-generated class that constructs the control hierarchy, the runtime would parse the
<%$ AppSettings:CopyrightNotice %>
and say, "Ah, I need to call the AppSettingsExpressionBuilder
class's GetCodeExpression
method in order to correctly assign the property value to this Label's Text
property." The GetCodeExpression
method would then be invoked.
The AppSettingsExpressionBuilder
class would see that the request was for the AppSettings key "CopyrightNotice". It would then return a CodeExpression
instance that specified the code to execute as AppSettingsExpressionBuilder.GetAppSettings("CopyrightNotice", typeof(Label), "Text")
. This code is actually injected
into the auto-generated class in the method that creates the Label and sets it properties.
Consider the code that is auto-generated if the Label's Text
property is assigned a static value, such as "Hello, World!" As we discussed earlier, it would look something like:
private global::System.Web.UI.WebControls.Label @__BuildControlCopyright() {
|
This is as we expect. But notice the code that gets generated when using an expression builder (namely <%$ AppSettings:CopyrightNotice %>
):
private global::System.Web.UI.WebControls.Label @__BuildControlCopyright() {
|
Look at that! The actual code specified via the CodeExpression
object in the AppSettingsExpressionBuilder
class is echoed into the code for the
auto-generated class. The AppSettingsExpressionBuilder.GetAppSettings
method, as you may have guessed, gets and returns the specified AppSettings value via the
ConfigurationManager.AppSettings
collection. The net result is that a developer can inject server-side information into the property of a Web control in the
declarative portion by using an expression builder. When the declarative markup is translated into code, the expression builder gets to inject code into this auto-generated
class, such as pulling a value from the AppSettings, returning the current date and time, or any other number of tasks.
Creating a Custom Expression Builder Class
The .NET Framework ships with three built-in expression builder classes:
AppSettingsExpressionBuilder
- retrieves a value from the AppSettings defined in the web application's configuration file.ConnectionStringsExpressionBuilder
- retrieves a value from the ConnectionStrings defined in the web application's configuration file.ResourceExpressionBuilder
- retrieves a resource value. Resources are commonly used to specify culture-specific values for localized applications.
ExpressionBuilder
class, which defines the base
functionality. Moreover, your class must implement, at minimum, the GetCodeExpression
class, whose duty it is to return a CodeExpression
object that
contains the code to inject when assigning the code expression to a Web control property in the auto-generated class.
Let's create a custom expression builder class named SessionExpressionBuilder
that allows page developers to declaratively assign Session variables to properties
of Web controls in the declarative markup. The idea here is that a page developer could display the value of a Session variable named, say, "Foo", in a Label control using the
following declarative markup:
<asp:Label runat="server" ... Text="<%$ Session:Foo %>" />
|
To start, we need to create a class that extends ExpressionBuilder
(which is found in the
System.Web.Compilation
namespace). Moreover, we need to override the
GetCodeExpression
method:
using System;
|
The GetCodeExpression method needs to return a CodeExpression
object, which can be one of any number of code generation tasks. For instance, the
CodeExpression
could perform a binary operation (such as addition), generate primitive expression (such as a literal string or number), or invoke a method,
among other options. We want the CodeExpression
to invoke a method so that the auto-generated class calls a method in our custom expression builder class when
assigning the expression builder value to the Web control property. For this reason, the GetCodeExpression
returns a CodeMethodInvokeExpression
object that calls GetRequestedValue
, a static method in the custom expression builder class:
public class SessionExpressionBuilder : ExpressionBuilder
|
The CodeMethodInvokeExpression
constructor accepts:
- The type that the method being called belongs to (
this.GetType()
, which returns the type of the custom expression builder class,SessionExpressionBuilder
) - The method name to invoke ("GetRequestedValue"), and
- The input parameters to pass into this method. We are passing in three parameters: the expression in the
<%$ expression %>
syntax, which is accessible via theExpression
property of theBoundPropertyEntry
object passed into theGetCodeExpression
method; the type of the Web control whose property is being assigned; and the name of the property being assigned.
GetRequestedValue
method, shown below, checks to ensure that the Session variable of interest exists. Next, it compares the type of the property being
assigned and the type of the Session variable being assigned to it. If there is a type mismatch it ensures that the Session variable type can be converted to the Web control
property type and then performs the conversion. If the two types match, it simply returns the Session variable value.
public class SessionExpressionBuilder : ExpressionBuilder
|
Before you can use the custom expression builder in your project you need to register it in Web.config
. Go to the <compilation>
element and
add the following:
<configuration>
|
Replace prefix with the expression builder prefix you want to use, such as "Session". Replace type with the type name of the custom expression builder class.
If you added it to the App_Code
folder in a Web Site Project the type is simply the name of the class, SessionExpressionBuilder
. If you are
using a Web Application Project or have the expression builder class in a separate Class Library project, the type should include the namespace and assembly, like so:
"namespace.SessionExpressionBuilder, assembly".
With this configuration information in place you can now use the expression builder in an ASP.NET page. For example, imagine that you had a page with a Label and you wanted to set the Label's Text and Font-Size properties based on Session variables "Message" and "MessageFontSize", respectively. You could use declarative markup like the following to achieve this:
<asp:Label ID="WelcomeMessage" runat="server" Text="<%$ Session:Message %>" Font-Bold="True"
|
When this page is visited and the declarative markup is translated into an auto-generated class, the class assigns the Label's Text
and Font.Size
properties a value returned by the SessionExpressionBuilder.GetRequestedValue
method. The code that gets auto-generated looks like the following:
@__ctrl.Text = System.Convert.ToString(SessionExpressionBuilder.GetRequestedValue("Message", typeof(System.Web.UI.WebControls.Label), "Text"), System.Globalization.CultureInfo.CurrentCulture);
|
The SessionExpressionBuilder.GetRequestedValue
method is grabbing the passed-in Session variable ("Message" and "MessageFontSize") from Session state and
returning its value, which is then assigned to the Label's Text
and Font.Size
properties.
Assuming that you have specified the values for these two Session variables previously in the user's session, the Label will incorporate these Session variables' values. The screen shot below shows a demo that's available for download at the end of this article. Prior to visiting this page the following code was executed:
Session["Message"] = "Welcome to My Website (FROM SESSION!)";
|
The result is that the Label's Text
property is set to "Welcome to My Website (FROM SESSION!)" and its Font-Size
property set to 48pt.

One Custom Expression Builder Library To Rule Them All!
It would have been nice if the .NET Framework had shipped with more expression builders. To address that shortcoming, I've decided to create my own library of custom expression builder classes that you are welcome to download and use in your projects. This library, named skmExtensionBuilders, is available for download at the end of this article, along with a demo website that shows these expression builders in action. (And, if you couldn't guess, it includes the
SessionExpressionBuilder
we just examined.)
To learn more about this library check out:
skmExpressionBuilders - A Suite of Custom Expression Builder Classes.
Until then... Happy Programming!
Attachments:
Further Reading
ExpressionBuilder
Class Technical Docs