How to build an Expression builder for ASP.Net 2.0

 

When you have read the posts on my blog, you have probably seen the new expression like the <% $ resource … %>, <% $ ConnectionStrings: Name %> etc.

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

If you have not seen them before, then take a look at this post on my blog.

 

You can build your own expression by inherits the ExpressionBuilder class. The ExpressionBuilder class has one method that must be implemented, GetCodeExpression.

 

The GetCodeExpression is used to return the code that will be evaluated during the parsing of the page to return the result of the expression.

 

You can also override the ExpressionBuilder’s EvaluteExpression method if you want your expression builder to be active on no-compile pages. This method most returns the results of the expression. If you implement the EvaluteExpression method, you must also override the SupportsEvaluate property, this property will return a Boolean value, and most return true if the EvaluteExpression method should be used.

 

In the example I’m going to show you, The "My" expression prefix is used:

 

<%$ My:MyExpression %>

 

MyExpression is the expression that is going to be sent to the custom expression builder as the value of the expression.

 

The following code is a very simple custom expression builder that will only return the expression that is specified after the "My" prefix:

 

using System;

using System.CodeDom;

using System.Web.UI;

using System.ComponentModel;

using System.Web.Compilation;

 

public class MyExpressionBuilder : ExpressionBuilder

{

    public MyExpressionBuilder()

    {

    }

 

 

    public static object GetData(string expression, Type targetType, string entryName)

    {

        return expression;

    }

 

 

    public override object EvaluateExpression(object target, BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)

    {

        return MyExpressionBuilder.GetData(entry.Expression, target.GetType(), entry.Name);

    }

 

   

    public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)

    {

        Type type1 = entry.DeclaringType;

        PropertyDescriptor descriptor1 = TypeDescriptor.GetProperties(type1)[entry.PropertyInfo.Name];

        CodeExpression[] expressionArray1 = new CodeExpression[3];

        expressionArray1[0] = new CodePrimitiveExpression(entry.Expression.Trim());

        expressionArray1[1] = new CodeTypeOfExpression(type1);

        expressionArray1[2] = new CodePrimitiveExpression(entry.Name);

        return new CodeCastExpression(descriptor1.PropertyType, new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(base.GetType()), "GetData", expressionArray1));

    }

 

 

    public override bool SupportsEvaluate

    {

        get

        {

            return true;

        }

    }

}

 

To use the custom expression builder, you have to register it to the web.config in the <expressionBuilders> section:

 

<configuration>

    <system.web>

       <compilation>

          <expressionBuilders>

              <add expressionPrefix="My" type="MyExpressionBuilder"/>

          </expressionBuilders>

       </compilation>

    </system.web>

</configuration>

 

The ExpressionPrefix attribute of the add element, is the name of the expression prefix:

 

<%$ expressionPrefixName: value %>

 

With the expressionPrefix set to "My", the expression would look like this:

 

<%$ My: value %>

 

The type attribute of the add element, is the type of the custom expression builder you have created. If you have added the custom expression builder to the /Code folder, you only need to write the name of the class. If you have created a separated class library, you have to enter the full name of the class and the assembly where the class exists.

 

Now let’s take a look at the code for MyExpressionBuilder.

 

First you need to add a method that will return the results for your expression, in this example the GetData method will be used to return the results of the expression:

 

public static object GetData(string expression, Type targetType, string entryName)

{

     return expression;

}

 

The code above is used to return the results of the expression argument. In this case it will return the value of the expression. The arguments of the GetData method, will contain the value of the expression, the targetType is the type of where the expression is bounded to, for example a TextBox control etc. The last argument, entryName, is the name of the property where the expression is bounded to. You can for example us the targetType to check if your expression is allowed for the property where the expression is specified.

 

As I mentioned earlier in my post, you can override the ExpressionBuilder’s EvaluteExpression method if you want your expression builder to be active on no-compile pages. The following code overrides the EvaluateExpression method and will call the GetData methoded described above:

 

public override object EvaluateExpression(object target, BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)

    {

        return MyExpressionBuilder.GetData(entry.Expression, target.GetType(), entry.Name);

    }

 

    public override bool SupportsEvaluate

    {

        get

        {

            return true;

        }

    }

 

 

The EvaluteExpression method has four arguments, target, entry, paresedData and context. I will only explain the one used in this example:

 

Target

 

The target arguments have the type of the type where the expression is bounded to.

 

Entry

 

The entry argument holds information about where the expression is bounded, such as the name of the property where the expression is bounded to, and the value of the expression etc.

 

As you can see in the code above, the method will do a call to the GetData method where the expression (value), the type of target and the name of the property where the expression is bound to are passed as arguments. By default the SupportEvalute property will return false, so to use the EvaluteExpression method, the SupportEvaluate property must be override and return true.

 

The next method to override is the GetCodeExpression. This method returns a CodeExpression class. It’s a class with the information about the method that will return the results for the expression, in this case the GetData method:

   

    public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)

    {

        Type type1 = entry.DeclaringType;

        PropertyDescriptor descriptor1 = TypeDescriptor.GetProperties(type1)[entry.PropertyInfo.Name];

        CodeExpression[] expressionArray1 = new CodeExpression[3];

        expressionArray1[0] = new CodePrimitiveExpression(entry.Expression.Trim());

        expressionArray1[1] = new CodeTypeOfExpression(type1);

        expressionArray1[2] = new CodePrimitiveExpression(entry.Name);

        return new CodeCastExpression(descriptor1.PropertyType, new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(base.GetType()), "GetData", expressionArray1));

    }

 

The method above will use the CodeCastExpression to specify a CodeExpression (The CodeCastExpression inherits the CodeExpression class). As you can see in the code above, I use the CodeCastExpression to specify the type of the property where the expression is bounded to, and the CodeTypeReferenceExpression to specify which method (GetData) that should be executed to get the results from for the expression. The argument to the GetData method is passed as a CodeExpression array where the items in the array are the value of the arguments that will be passed to the GetData method. I don’t think I need to write more about that, you will probably understand the code, if not, please don’t hesitate to contact me.

 

Here is an example how you can use the custom expression provider:

 

<asp:textbox Id="test" runat="server" Text='<%$ My: Welcome%>'></asp:textbox>

 

When you run this code, the TextBox’s Text property will have the value set to "Welcome".

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章