Here’s a pain: write an ASP.NET ExpressionBuilder. Here’s another: use a ValidationExpression for a RegularExpressionValidator which isn’t hard-coded, Resource based or App Settings based, but code based. This post will cover both pains, but will open a “world of options” for using custom ASP.NET Expressions.
To those unfamiliar with ASP.NET Expressions, here’s a brief: you can set property values in a declarative way using Expressions. For example:
<asp:Label runat="server" Text="<%$Resources: Description %>"/>
Assuming that you have a corresponding resource file, the user will see the value set there for the item that has the Description key. I won’t get into this in this post, but I’m a big fan of using Resources in ASP.NET, so Expressions are something I use often.
ASP.NET comes with 3 out-of-the-box Expression “types”: Resources, Connection Strings and App Settings.
The RegularExpressionValidator Situation (Pain number 2):
I assume that most of us who develop using WebForms and ASP.NET Validators have used the RegularExpressionValidator at some point. Using the ValidationExpression property, we can easily set a Regular Expression to validate our users input for stuff like emails, phone numbers, zip codes etc. Very comfortable:
However, a ValidationExpression has to be either hard coded, or retrieved using an Expression. This means that if you need to use the same regular expression in different locations, you’ll either have to copy-paste it, or use an Expression based solution. Hard-coding and copy-pasting a ValidationExpression could prove to be a bad practice, especially for generic validations such as emails and the like, because you may want to change the tested expression, and in such a case you’ll have to find all those locations you now have to replace. Using Expressions is a better solution because by placing a regular expression in a Resource file or App Settings, you can at least avoid copy-pasting it and you have single location where changes can be made. However, both of these Expression-based solutions are somewhat an ugly workaround, because you’d usually want your regular expression in a Shared/Common dll, so other components may use it, and not only your ASP.NET validators. While AppSettings can still be used across your different assemblies, Resources cannot (well, you can use Reflection but that’s another story). Finally, your expression may reside in a Property and contain logic, so now you have to have a code based solution. For example, let’s assume that you need a regular expression validation which is culture oriented – you probably have to use thread culture code to accomplish that. Unfortunately, you cannot use server side script tags to fetch a static, const or property. For some reason I’m not familiar with, MS has not provided what should have been one of the most basic features in ASP.NET, and that is to use the <%= %> from within declarative syntax:
Anyhow, if you do want to use a regular expression placed in a const, static field or a static property as written in the following code, you are now stuck, or you are forced to code-behind this in your page and give up the declarative ValidationExpression.
StaticExpression (Pain number 1):
I decided to overcome this situation using a custom Expression. I have written just a small number of expressions all these years, and each time I found myself wasting precious time on remembering how to do this, googling for sample code etc. There are several good resources on the web for writing custom Expressions. Here’s one and another from MS. To summarize this, I’ll just say that basically there are 4 steps to writing your own a custom expression:
- Write a custom Expression class by inheriting from ExpressionBuilder (e.g. StaticExpression class that will accomplish retrieving static, const or Property values).
- This class should have a static method which actually performs what you want to do and return the desired string.
- This class should also implement the abstract GetCodeExpression( ) method, which simply uses CodeDom objects to call the method you created in step 2. (Note, that you may choose to implement the code directly from this method and skip the static method in step 2, as shown in MS’ sample).
- Add the custom Expression to the web.config, so that ASP.NET will now how to resolve the declarative Expressions in your pages.
Here is the StaticExpression class, which supports returning a string from a const or static field/property using simple Reflection (explanation below). I placed this class in the App_Code:
- Lines 9-18 is the CodeDom method which returns the custom method which actually does all the work (lines 20-71).
- Lines 26-35 parse and determine whether the expression contains not only the class and field/property, but also an assembly name where to retrieve it from. Note, that you can alternatively change the code so that if no assembly is specified, some default assembly is used (in such a case you’ll have to insert a line of code adjacent to line 34, which states: assemblyName=”<your default assembly name>”.
- Lines 29-30 assumes that the expression specifies an assembly, and that the assembly is specified prior to the const/property. This resembles working with Global Resources, but this doesn’t have to be the case. You may choose to specify the assembly after the const/property name, resembling how Reflection’s Type.GetType work (line 47 shows this).
- Lines 38-47 resolves the type of the class to be used. The expression, without the assembly, is parsed so that we’ll have the class (including namespace if specified) separated from the field/property name.
- Line 50 retrieves the actual class type.
- Lines 54-58 attempt to detect if the name relates to a static field or const, and retrieve it’s value (the null in Line 57 implies a static field or a const).
- Lines 59-64 relate to properties (the first null in Line 63 implies a static property and the second null means that there are no arguments to this property).
- Lines 67-68 will throw an exception if the text could not be retrieved.
The declarative code in your Page:
- The Label’s Text demonstrates how to retrieve MyConst const from a Consts class residing in the App_Code (no assembly specified).
- The RegularExpressionValidator’s ValidationExpression demonstrates how to retrieve a static Property value from a class residing in a different assembly.
And the web.config, which states that when a “Static” keyword is used for an Expression, resolve it using the StaticExpression class:
You may also choose to inherit ResourceExpressionBuilder instead of the abstract ExpressionBuilder. This could be handy if you need a custom Expression that will fallback to resolving a Resource Expression. For example, if your page is running in two different custom modes, X and Y, you could change the resource key stated in the declarative property and only then proceed to retrieving the resource, by calling the base class methods. Your code will require changes, but it’s certainly achievable.