ASP.NET Web Forms Extensibility: Expression Builders
I have talked extensively about expression builders in the past, and that is because I find them extremely useful, for building no code solutions.
In a nutshell, it is a design-time mechanism for executing a method which receives some parameters and returns something that will be bound to a control’s property. Anyone who has used resources – <%$ Expression:xxx %> -, bound a connection string or an application setting to a data source control – <%$ ConnectionStrings:xxx %> and <%$ AppSettings:xxx %> – on an ASP.NET page has used expression builders. These expression builders are included with ASP.NET, and do useful things, such as returning a connection string or an application setting from the configuration file, or returning a translated resource according to the current browser culture, without the need to code.
One example would be, for example, picking up some value from the current HttpContext and assigning it to some control’s property. Here’s a simple way to achieve it, using DataBinder.Eval to process possibly complex expressions:
1: public class ContextExpressionBuilder : ExpressionBuilder
3: #region Public static methods
4: public static Object GetValue(String expression, Type propertyType)
6: HttpContext context = HttpContext.Current;
7: Object expressionValue = DataBinder.Eval(context, expression.Trim().Replace('\'', '"'));
9: expressionValue = Convert(expressionValue, propertyType);
11: return (expressionValue);
16: #region Public override methods
17: public override Object EvaluateExpression(Object target, BoundPropertyEntry entry, Object parsedData, ExpressionBuilderContext context)
19: return (GetValue(entry.Expression, entry.PropertyInfo.PropertyType));
23: #region Protected static methods
24: protected static Object Convert(Object value, Type propertyType)
26: if (value != null)
28: if (propertyType.IsAssignableFrom(value.GetType()) == false)
30: if (propertyType.IsEnum == true)
32: value = Enum.Parse(propertyType, value.ToString(), true);
34: else if (propertyType == typeof(String))
36: value = value.ToString();
38: else if ((typeof(IConvertible).IsAssignableFrom(propertyType) == true) && (typeof(IConvertible).IsAssignableFrom(value.GetType()) == true))
40: value = System.Convert.ChangeType(value, propertyType);
45: return (value);
49: #region Public override methods
50: public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, Object parsedData, ExpressionBuilderContext context)
52: if (String.IsNullOrEmpty(entry.Expression) == true)
54: return (new CodePrimitiveExpression(String.Empty));
58: return (new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(this.GetType()), "GetValue"), new CodePrimitiveExpression(entry.Expression.Trim()), new CodeTypeOfExpression(entry.PropertyInfo.PropertyType)));
63: #region Public override properties
64: public override Boolean SupportsEvaluate
68: return (true);
As you can see, there are two methods that may be called in order to retrieve a value:
In this example, I have implemented both methods, so that it can be used in various scenarios. On the GetCodeExpression method I simply return a Code DOM expression that calls the static method GetValue on my expression builder. I have a method that tries to convert the returned value into the target property on the declaring control, in case they are of different types.
Expression builders need to be registered on the Web.config file, on the expressionBuilders section:
5: <add expressionPrefix="Context" type="MyNamespace.ContextExpressionBuilder, MyAssembly"/>
Finally, here’s how to use this sample expression builder to feed a Label text on a markup file:
1: <span>Value of cookie MyId: <asp:Label runat="server" Text="<%$ Context:Request.Cookies['MyId'].Value %>" /></span>
This is identical to having the following code:
1: myLiteral.Text = HttpContext.Current.Request.Cookies["MyId"].Value;
The syntax is <%$ MyRegisteredPrefix: SomeString %>, where MyRegisteredPrefix is what you want it to be, and what is registered on Web.config, and SomeString is also a randomly-formed string. Note that the expression builders forbid us to using “ in this string, so, what I did was allow ‘ to be used instead, and replace them at runtime.
What remains to be said is regarding editors for allowing integrated expression builder design inside Visual Studio, but since that is strictly not required, I leave it to some other time.
As usual, hope you find this of use. Look for the other expression builders that I wrote, all code is available on the blog.