Wednesday, August 9, 2006 4:15 PM InfinitiesLoop

The CodeExpressionBuilder

A very exciting new feature in ASP.NET 2.0 is Expression Builders. Expression builders allow for some pretty interesting interaction with the ASP.NET compilation model.

For example, new to ASP.NET 2.0 is the ability to reference appSettings declaratively. Lets say you wanted the text of a button to be based on a value in the appSettings section of your web.config. Piece of cake:

<asp:Button id="cmdSubmit" runat="server" Text="<%$ appSettings: ButtonText %>" />

This is made possible by the built in AppSettingsExpressionBuilder. Lets say you wanted to display a localizable string, which is stored as a resource. In ASP.NET 1.1 it was sort of a pain. No longer:

<%$ resources: ResourceKey %>

That's the ResourceExpressionBuilder hard at work. Nice!

There's also a ConnectionStringExpressionBuilder so you can refer to Connection Strings defined in the new connection strings section in the web.config. That is extremely helpful when working with the new declarative data controls:

<asp:SqlDataSource id="data1" runat="server"
    ConnectionString="<%$ ConnectionStrings: MyConnectionString %>"/>

Pretty useful.

Now lets take it one step further. Have you ever seen this exception?


The dreaded "Server tags cannot contain constructs" exception.

That's because you probably tried to do something like this:

<asp:Label id="lbl1" runat="server" Text=<%= CurrentUserName %> />

Perhaps you tried to fix it by putting it in quotes:

<asp:Label id="Label1" runat="server" Text="<%= CurrentUserName %>" />

... Only to be thwarted once again, as the literal text, including the <%= %> construct, ended up in the page:


Putting <%= %> in quotes doesn't help much.

If all you want to do is show the result of this code as a string, you could quite simply just get rid of the label:

<%= CurrentUserName %>

That would work. But perhaps you need the label server control for some other reason, or perhaps you need to set a string property of some other type of server control in this way.

The problem is you have incorrectly (although intuitively) tried to assign the property of a server control using the <%= %> construct. Unfortunately that is simply not supported by ASP.NET, 1.1 nor 2.0. If you ask around about your problem, someone may tell you that you will have to convert to using the <%# %> databinding construct instead. That is advice that I have given myself. But it requires that you are calling DataBind() on the control, AND, it will cause you to BLOAT VIEWSTATE... and you KNOW how much I hate bloating viewstate!

You can just go ahead and assign the value in your code-behind, say.. in the OnInit method.. but that too will bloat viewstate. I'm afraid there's no super simple solution unless you don't mind disabling viewstate on that control. That may work in some scenarios, but sometimes you really need the ViewState enabled! What's a web developer to do?

Let me back up a little and give a more concrete example. You want the text value of a CheckBox to be the current date and time. For whatever reason, you can't disable viewstate on the CheckBox (say, because you need the CheckChanged event, which doesn't work without viewstate). How on Earth are you going to get the current date and time into the Text property on the CheckBox, WITHOUT BLOATING VIEWSTATE? By "Bloating ViewState", I mean causing data to become serialized in the __VIEWSTATE hidden form field when it isn't necessary to begin with. There's no reason to put the current Date and Time into serialized viewstate, is there? It's going to be reassigned on the next request. You'd just be making ASP.NET serialize it, then making the user's browser pull the serialized string down the pipe, then making them push it back up the pipe to the server on a postback, then making ASP.NET deserialize the value -- ONLY FOR IT TO BE REASSIGNED? How rude! How wasteful and inefficient. For a single control its not a big deal, what's a few bytes? But that is not a path you want to start down my friend... with that kind of mantra, your web forms will quickly grow a viewstate tumor the size of a Borg cube! Ideally, you want the functional equivalence of this:

<asp:CheckBox id="chk1" runat="server" Text="<%= DateTime.Now %>"/>

That is ideal, because the ViewState StateBag is not tracking changes when ASP.NET assigns declared attributes, so our beloved ViewState remains optimized. And, we didn't even have to disable ViewState. AND we can do it declaratively! Woohoo! Right. Well, it won't work.

The CodeExpressionBuilder comes to the rescue! Another great thing about ExpressionBuilders is that you can roll your own. So, I created a CodeExpressionBuilder, one that allows you to use raw code to assign values to control properties. Using the CodeExpressionBuilder you can do this:

<asp:CheckBox id="chk1" runat="server" Text="<%$ Code: DateTime.Now %>"/>

Now that is nice. And to think the darn thing is only a few lines of code! The trick is to use the CodeDom's CodeSnippetExpression to convert the given string into a CodeExpression. Here's the entire class:

[ExpressionPrefix("Code")]
public class CodeExpressionBuilder : ExpressionBuilder {
    public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, 
       object parsedData, ExpressionBuilderContext context) {
        return new CodeSnippetExpression(entry.Expression);
    }
}

To use it, or any custom ExpressionBuilder for that matter, you must register it in the web.config expressionBuilders section. Now... how you do this part sort of depends on how your project is setup. If you have a standard ASP.NET Web Site project, then you will be defining the CodeExpressionBuilder class in the app_code directory, and the "type" will just be "CodeExpressionBuilder". However, if you are creating a Web Application Project (read about it here), then the CodeExpressionBuilder is just another class in your project, with its own namespace. For that you will need to define the whole type string (or, if you define it in a reusable library, you'll need the fully qualified type and assembly name). In my case that is "Infinity.Web.Compilation.CodeExpressionBuilder". Like this:

<compilation debug="true">
  <expressionBuilders>
    <add expressionPrefix="Code" type="Infinity.Web.Compilation.CodeExpressionBuilder"/>
  </expressionBuilders>
</compilation>

And to see it in action:

<asp:CheckBox id="chk1" runat="server" Text="<%$ Code: DateTime.Now %>" />

ExpressionBuilders are truly a thing of beauty! Use any expression you want!

Also try:

<%$ Code: DateTime.Now.AddDays(1) %>
<%$ Code: "Hello World, " + CurrentUserName %>
<%$ Code: CurrentUserName.ToUpper() %>
<%$ Code: "Page compiled as: " + this.GetType().AssemblyQualifiedName %>

Just be careful what combination of quotes you use. If you have literal strings in your code expression like in two of the above examples, you will need to use single quotes (') to surround the entire <%$ %> expression if it is within a server control declaration. If you don't you will get the "Server tag is not well formed" error.

In the beginning I said ExpressionBuilders were an interesting way to plug into the ASP.NET compilation model. Well this really illustrates that... put a break point in the expression builder, and debug the page. You will hit the break point once, and only once, even after you refresh the page several times. The Date and Time will continue to update, but the expression builder breakpoint will only activate the first time you hit the page. The reason is because the ExpressionBuilder is used when ASP.NET compiles the page. Once the page is compiled, that's it. That's the reason why ExpressionBuilder returns a CodeExpression, and not an actual object. In essence, the builder tells ASP.NET what code it needs to run to get the value, instead of giving it the actual value. It's the old adage, teach a man to fish, and he eats forever. How geeky is that? Too cool.

PS: The one thing this ExpressionBuilder doesn't do... it won't work in "No-Compile" pages. Seems like a reasonable limitation.

Questions? Comments? Random odd facts?

HAPPY (dynamic) CODING!

UPDATE 09/05/2006: Thanks to the tip from Kelly, made the code even shorter. Also fixed a typo in the web.config snippet. The "Type" attribute should be lower case, "type".

Filed under: , ,

Comments

# re: The CodeExpressionBuilder

Thursday, August 10, 2006 9:08 AM by Potiguar

Pretty cool indeed. Keep the good posts coming, man!

# re: The CodeExpressionBuilder

Monday, August 14, 2006 4:42 AM by -

Couldn't get an expression builder registered from an external assembly.

# re: The CodeExpressionBuilder

Monday, August 14, 2006 12:15 PM by InfinitiesLoop

What issue were you having Mr. Anon? If you send me what you've got maybe I can help.

# re: The CodeExpressionBuilder

Thursday, August 17, 2006 11:19 AM by MartinF

You are truly a badass.

Thanks for the articles, they are great (this one and the one about the viewstate).

Also thanks for the Darkside theme. I will try it out.

# re: The CodeExpressionBuilder

Tuesday, September 5, 2006 6:04 PM by Kelly

Is there any reason why you couldn't drop 'ParseExpression' and use 'entry.Expression' in 'GetCodeExpression' instead?

# re: The CodeExpressionBuilder

Tuesday, September 5, 2006 7:32 PM by InfinitiesLoop

Kelly -- you're absolutely right, ParseExpression is not necessary. I updated the code in the article. Now it really is only a few lines long. Thanks :)

# re: The CodeExpressionBuilder

Friday, September 8, 2006 3:41 PM by Deken

So, what about using it for something other than Text output like setting a property on the control?  For example:

<asp:CheckBox id="chk1" runat="server" Text="button" Visible='<%$ Code: Datetime.Now.Day==1 %>' />

# re: The CodeExpressionBuilder

Friday, September 8, 2006 4:08 PM by InfinitiesLoop

Yeah, no problem. You can set any property with it, as long as the expression returns the correct data type. There's nothing special about the Text property on a checkbox, just happened to be the example I used.

# re: The CodeExpressionBuilder

Thursday, September 21, 2006 4:33 AM by David

Hi,

I'm just doing a migration from a Web Site projet to a Web Application projet following the same link you provide in your article.

I use an ExpressionBuilder and the tag I use in the web.config is quite the same as yours, i.e. something like that:

<expressionBuilders>

<add expressionPrefix="Code" type="MyNameSpace.MyExpressionBuilderClass"/>

</expressionBuilders>

When I launch th emigration on the ascx control that uses this expression builder I got the foloowing error:

Could not load type 'MyNameSpace.MyExpressionBuilderClass' from assembly 'System.Web'

It tries to load my expression builder from the assembly System.Web !!

And if I add the name of my own assembly in the fully qualified name of my expression builder type, it doesn't work either...indeed, my web application doesn't compile since this ascx control has not been converted...

Any Idea about this issue?

Thanks,

David

# re: The CodeExpressionBuilder

Monday, September 25, 2006 2:55 PM by InfinitiesLoop

Gareth -- the namespace is actually System.Web.Compilation, not Configuration. Try that.

You also need System.CodeDom.

As for the arrow keys... you mean while typing in the comment box, you can't go up/down? It works for me... what browser are you using?

# re: The CodeExpressionBuilder

Sunday, October 15, 2006 12:59 AM by leafyoung

After create the IdExpressionBuilder like following code, i found the ClientID just equals to ID, even the control is in a user control, do you know why? (my english is limited, sorry)

// IdExpressionBuilder.cs in APP_Code

using System;

using System.CodeDom;

using System.Web.UI;

using System.Web.Compilation;

using System.Web;

namespace Monster.Web

{

   [ExpressionPrefix("clientID")]

   public class IdExpressionBuilder : ExpressionBuilder

   {

       public override CodeExpression GetCodeExpression(BoundPropertyEntry entry,

           object parsedData, ExpressionBuilderContext context)

       {

           return new CodeSnippetExpression(entry.Expression + ".ClientID");

       }

   }

}

//WebUserControl1.ascx

<%@ Control Language="C#" ClassName="WebUserControl" Debug="true" %>

<asp:Button ID="Button1" runat="server" Text="Button" />

<asp:TextBox ID="TextBox1" runat="server" Text="<%$ clientID: Button1 %>"></asp:TextBox>

# re: The CodeExpressionBuilder

Sunday, October 15, 2006 1:14 PM by InfinitiesLoop

The unique ID and client ID of a control isn't established until its part of the control tree. Expressions are evaluated before they are added to the control tree, so its too soon. You could just use the databinding syntax instead, <%# button1.ClientID %>, and then be sure to call DataBind.

# re: The CodeExpressionBuilder

Wednesday, October 18, 2006 3:02 PM by Phil

Nice article.

Can you clarify when in the event life cycle the expressions are evaluated.  I set a variable during Page_Load. However the expression evaluates to what the variable was initialized to in the Dim declaration.  I should mention I'm trying to pass a dynamic value to a custom control like

<sd:DateFieldWithCalendar name="startdate" value="<%$ Code: StartDate %>" runat="server" />

# re: The CodeExpressionBuilder

Wednesday, October 18, 2006 5:27 PM by InfinitiesLoop

Phil, the expressions are evaluated at the same time the other markup attributes are evaluated, which is during the creation of all the controls on the page (very early: before OnInit).

In other words, this is only meant for dynamic data is immediately available or calculable. So if you can call say GetStartDate() and have that method return the correct value even if its before the page OnInit method, great.

If not, then your data is best suited for DataBinding. Use <%# GetStartDate() %> and then call DataBind on that control when you want it to execute, such is in OnLoad on !IsPostBack.

# re: The CodeExpressionBuilder

Tuesday, December 19, 2006 7:22 PM by Dan

I'm new to ASP so I've probably missed something but when I run my app, i get the following " Compilation Error..."

Line 14: ///

Line 15: [ExpressionPrefix("Code")]

Line 16: public class CodeExpressionBuilder : ExpressionBuilder {

Line 17:     public override CodeExpression GetCodeExpression(BoundPropertyEntry entry,

Line 18:         object parsedData, ExpressionBuilderContext context) {

# re: The CodeExpressionBuilder

Tuesday, December 19, 2006 7:51 PM by InfinitiesLoop

Dan -- you didn't paste the compilation error itself. You are probably seeing squigly lines under all the types it doesn't recongize. You need to make sure you are 'using' all the namespaces that are needed.

to the top of the code file add:

using System.Web.Compilation;

using System.CodeDom;

in addition to whatever using statements you already have.

# re: The CodeExpressionBuilder

Tuesday, January 16, 2007 12:59 PM by foobar

Yeah, I figured this out a few months ago as well.

Thing is, I hate having bits of code strewn about the page.  It really makes maintenance harder.

This was one of the reasons I stopped using ColdFusion.  There's code just littered everywhere in a typical CF page, and when you're looking at some total train wreck of a page that someone wrote two years ago, it becomes really, really hard to figure out what's going on.

# re: The CodeExpressionBuilder

Wednesday, January 24, 2007 2:03 PM by DalKinz

Awesome, you just saved me a lot of hassle. Thanks!

# re: The CodeExpressionBuilder

Thursday, February 15, 2007 10:33 PM by Herb

It is great, it help me to solve most of my problem.

It works on the text on buttons and textbox,

however, it is not work on the OnClientClick event

<asp:Button ID="showDate" runat="server" Text="Show Date" UseSubmitBehavior="false" OnClientClick="alert('<%$ Code: DateTime.Now %>');" >

Can it also be solved?

# re: The CodeExpressionBuilder

Thursday, February 15, 2007 11:56 PM by InfinitiesLoop

Herb, you have to understand that the expression applies to an entire property value, you can't intermix multiple expressions.

so you can do it by including everything in the expression itself:

(assuming C# here)

OnClientClick='<%$ Code: "alert(\"" + DateTime.Now + "\");" %>'

It may look confusing with all those quotes. The expression itself is a string (javascript), which contains quotes (the parameter to alert), which contains dynamic data (the server date) outside of the quotes.

# re: The CodeExpressionBuilder

Friday, February 16, 2007 12:31 PM by InfinitiesLoop

Marvin - 'currentusername' was just an example I was using, it isnt a built in function. You'll have to create the logic for getting the current user's name yourself, which can depend on what authentication mechanism you are using.

# re: The CodeExpressionBuilder

Friday, May 11, 2007 7:45 PM by Zubair

It works great,  if I type it in the html view. In the properties window however, this expression does not show up.  If I go to the expressions window after typing the expression in html view, It alerts me like "TextBox1 Expressions \n The Expression prefix 'Code' was not found in the config. \n You will need to add an <expressionBuilder> definition to your config file for the page to function properly." thanks.

# re: The CodeExpressionBuilder

Monday, May 21, 2007 12:08 PM by Brian

Could something explain the '

# re: The CodeExpressionBuilder

Friday, June 15, 2007 9:36 PM by Ken

hi. great post by the way ... i'm trying to make it work in a button control like: ') repeat-x;" runat="server" /> i also tryied: ') repeat-x;" runat="server" />, but then i get a not well formed tag any ideas how to fix it?

# re: The CodeExpressionBuilder

Friday, June 15, 2007 10:05 PM by InfinitiesLoop

What is up with these nested comments ... ugh.

Ken -- the expression has to apply to the entire property value, not just a part of it.

wrong:

foo="abc<%$ Code: bar() %>xyz"

right:

foo='<%$ Code: "abc" + bar() + "xyz" %>'

# re: The CodeExpressionBuilder

Tuesday, June 19, 2007 3:20 PM by Hank

Can this be used to set a sqldatasource connectionstring

dynamically?

Thanks!

# re: The CodeExpressionBuilder

Tuesday, June 19, 2007 3:44 PM by InfinitiesLoop

Yes -- any property can be set with it. Just keep in mind that the property will be set very very very early in the request -- before OnInit even. So don't expect the value to be able to depend on anything dynamic, unless its something you can determine prior to OnInit.

# re: The CodeExpressionBuilder

Saturday, August 4, 2007 12:58 PM by silpheed

w00t! This is exactly what I needed. Thanks!

# re: The CodeExpressionBuilder

Wednesday, August 15, 2007 7:45 PM by Scooby

Thanks for the great post!  The CodeExpressionBuilder has been very useful in the project I'm working on.

I use it mostly for dynamically displaying controls based on a user's role (e.g. - I set the visible property to '<%$ Code: User.IsInRole("Administrator")%>').  I know that this works, but I'm not exactly sure why.  As specified in previous posts, the expression gets evaluated very early on in the lifecycle.  My question is that I'm not exactly sure when the Page's properties (in this case "User") get set.  Must be early on since the code works, but I was hoping you could give a more precise explanation?

Thanks again!

# re: The CodeExpressionBuilder

Sunday, August 26, 2007 4:46 PM by Jelle

I get next error:

Literal expressions like '<%$ Code: Localization.GetString("btnCopy",LocalResourceFile)%>' are not allowed. Use <asp:Literal runat="server" Text="<%$ Code: Localization.GetString("btnCopy",LocalResourceFile)%>" /> instead.

I try to load a control dynamically with this code in a linkbutton:

       <asp:LinkButton ID="btnCopy" runat="server" CausesValidation="true"

           OnClick="btnCopy_Click">  <img src='<%$ Code: ImageBtnCopy%>'                 alt='<%$ Code: Localization.GetString("btnCopy",LocalResourceFile)%>'  />            

       </asp:LinkButton>

# re: The CodeExpressionBuilder

Sunday, August 26, 2007 8:25 PM by InfinitiesLoop

Jelle -- you should do what the error message suggests. It's saying you can't have free-floating expressions like that, they need to be expressed as properties of server controls. Using a literal control to do that would do the same thing you intended but with a server control.

# re: The CodeExpressionBuilder

Tuesday, August 28, 2007 2:13 PM by Javier

Any ideas why I get this? (I have validated that the assembly is in the assemblies section)

Parser Error Message: Could not load type 'iTmove.Web.Compilation.CodeExpressionBuilder'.

Source Error:

Line 35:       </assemblies>

Line 36: <expressionBuilders>

Line 37: <add expressionPrefix="CodeExpr" type="iTmove.Web.Compilation.CodeExpressionBuilder"/>

Line 38: </expressionBuilders>

Line 39: </compilation>

# re: The CodeExpressionBuilder

Tuesday, August 28, 2007 3:08 PM by InfinitiesLoop

Javier -- verify the type name is correct. Verify the assembly is in the bin or gac. Verify that the assembly can be loaded in the app, e.g. that it not missing any dependencies. Try adding the assembly name in the type attribute for good measure ("typename, assemblyname[, strongname]"), although being in the assemblies section I think should prevent the need for it, but worth a shot.

# re: The CodeExpressionBuilder

Wednesday, August 29, 2007 2:08 PM by fm

You mentioned that using the data binding syntax (<%# %>) would bloat ViewState.

If you call DataBind inside OnInit before ViewState is tracking, will that still bloat ViewState?  If so, can you explain why?

# re: The CodeExpressionBuilder

Wednesday, August 29, 2007 4:43 PM by InfinitiesLoop

fm --

From within OnInit, the control or page's OWN viewstate is not yet tracking, but child controls ARE. That's because OnInit occurs in reverse order -- by the time your OnInit occurs, your child controls have already gone through OnInit and have begun tracking.

The only way to to programmatically set the property of a child control before it is tracking viewstate without using a derived control specifically for that purpose is to do it from page PreInit, handling the Init event of the control and doing it from the handler, or catch it when its added to the page by overriding AddedControl in its parent.

# re: The CodeExpressionBuilder

Friday, September 7, 2007 12:46 AM by Phill

Hey there, ignore my last question (but not the compliments and thanks!) Solved my own problem, had a litteral inside the quotes of the tag, just moved it to within the expression. Knew it wasn't allowed as you stated above, just didn't see it. So went from ErrorMessage='*<%$ Code: Getstring("test") %>' to ErrorMessage='<%$ Code: "*" + Getstring("test") %>'

It's late, thankfully I figured it out so now I can sleep...

Cheers,

Phill

# re: The CodeExpressionBuilder

Monday, September 17, 2007 3:17 PM by julianmj

Hi, thanks for to code and the amazing article TRULY Understanding ViewState.

I have something like this:

<asp:SiteMapPath ID="MapaBasico" runat="server" SiteMapProvider="<%$ Code: Session[0].ToString()%>"></asp:SiteMapPath>

and this:

if (Session[0].ToString() == "")

               Response.Redirect("~/Inicio.aspx");

When the session is null I redirect to Inicio.aspx, but asp evaluates  this first. So when session is null I get an error. ¿How can I avoid that?

<asp:SiteMapPath ID="MapaBasico" runat="server" SiteMapProvider="<%$ Code: Session[0].ToString()%>"

Thanks.

# re: The CodeExpressionBuilder

Monday, September 17, 2007 3:28 PM by InfinitiesLoop

try this:

<%$ Code: Session == null ? "" : Session[0] %>

You shouldn't need the ToString call in there, ASP.NET takes care of converting expressions to the property type.

# re: The CodeExpressionBuilder

Monday, September 17, 2007 3:30 PM by InfinitiesLoop

Oh and use single quotes (') instead of double quotes to contain that expression, since it contains double quotes. Or you'll get an error about the server tag not being well formed.

# re: The CodeExpressionBuilder

Tuesday, September 18, 2007 3:09 PM by julianmj

hey thanks, but I have to do this instead.

<%$ Code: Session.Count == 0 ? "" : Session[0] %>

Anyway, I learn how to use conditions with your answer,

¿What else can I do?

Again, thanks and excelent work, I'm reading all your articles and they are great.

# re: The CodeExpressionBuilder

Tuesday, October 2, 2007 1:16 PM by Darragh

Very interesting article, but I'm not sure about when in the event life cycle this actually happens. You said....

"Phil, the expressions are evaluated at the same time the other markup attributes are evaluated, which is during the creation of all the controls on the page (very early: before OnInit)."

Howerver, regular scriplets on the page execure AFTER page_load.

Therefore if i assign a value to StartDate in page_load the following works....<%=Date.Now %>

Howerver the following does not work...

<custom:control ruant="server" value="<% Code: StartDate %>" />

# re: The CodeExpressionBuilder

Tuesday, October 2, 2007 1:30 PM by InfinitiesLoop

Darragh -- when I say at the same time as other attributes, I don't mean <%= %> code blocks. Those run during RENDER, very late in the life cycle. Expressions specified with <%$ %>, whether they are this code expression builder or any other, are executed when the control tree is first created, which is one of the very first things that happens in the life cycle. If you need it to execute later, you'll have to use some other means, like databinding with <%# %>.

# re: The CodeExpressionBuilder

Wednesday, October 3, 2007 4:48 AM by Darragh

Ok, thanks for your speedy reply. I understand better now. I just with I could get these server control propreties to evalute during render, same as other code blocks.

# re: The CodeExpressionBuilder

Wednesday, October 17, 2007 3:48 PM by Patty

You say above that the ConnectionString property is no different from any other, and that was my theory, too.  I've created my own expression builder for use in the ConnectionString property of a SqlDataSource declarative object.  It runs fine, but Visual Studio doesn't understand it.  I get a blue squiggly in the codebehind with the error: &quot;ProductMembersDataSource is not a member of my_page.aspx.&quot;

I wonder if you've ever seen this, and if so, do you know what I might be doing wrong?  Thanks!

It's declared in web.config:

<code>

&lt;expressionBuilders&gt;

&lt;add expressionPrefix="MyExp" type="MyExpressionBuilder"/&gt;

&lt;/expressionBuilders&gt;

</code>

I use it in an .aspx page:

<code>

   &lt;asp:SqlDataSource ID="ProductMembersDataSource" runat="server" SelectCommand="mgr_getProdMembers" ConnectionString="&lt;%$ MyExp: ProductConnectionString %&gt;" ProviderName="System.Data.SqlClient" SelectCommandType="StoredProcedure" CacheDuration="10"&gt;

       &lt;SelectParameters&gt;

           &lt;asp:ControlParameter ControlID="Hidden_PID" Name="pid" PropertyName="Value"

               Type="String" /&gt;

       &lt;/SelectParameters&gt;

   &lt;/asp:SqlDataSource&gt;

</code>

And the class is defined in app_code/MyExpressionBuilder.vb:

<code>

Public Class MyExpressionBuilder

   Inherits ExpressionBuilder

   Public Overrides Function GetCodeExpression(ByVal entry As System.Web.UI.BoundPropertyEntry, ByVal parsedData As Object, ByVal context As System.Web.Compilation.ExpressionBuilderContext) As System.CodeDom.CodeExpression

       Dim param As String = parsedData(0) 'entry.Expression

       Dim args As String() = CType(parsedData, String())

       HttpContext.Current.Trace.Write("GetCodeExpression", String.Format("Length of parsed args is {0}", args.Length))

       Dim x As New MyData.ConnectionDictionary

       Dim ret As New CodePrimitiveExpression()

       HttpContext.Current.Trace.Write("GetCodeExpression", String.Format("Fetching expression for {0}", param))

       Select Case param

           Case "ContextConnectionString"

               ret.Value = Me.ConnectionLibrary.Context

           Case "NavigationConnectionString"

               ret.Value = Me.ConnectionLibrary.Navigation

           Case "OrderConnectionString"

               ret.Value = Me.ConnectionLibrary.Order

           Case "ProductConnectionString"

               ret.Value = Me.ConnectionLibrary.Product

           Case "ShopperConnectionString"

               ret.Value = Me.ConnectionLibrary.Shopper

           Case "ConnectionString"

               ret.Value = Me.ConnectionLibrary.Product

           Case Else

               ret.Value = HttpContext.Current.Application(param)

       End Select

       Return ret

   End Function

   Public Overrides Function ParseExpression( _

   ByVal expression As String, _

   ByVal propertyType As Type, _

   ByVal context As ExpressionBuilderContext _

       ) As Object

       Dim l_exp As String() = expression.Split(New Char() {"(", ",", ")"})

       For Each x As String In l_exp

           HttpContext.Current.Trace.Write("Parsing Expression", x)

       Next

       Return l_exp

   End Function

   Private Function ConnectionLibrary() As MyData.ConnectionDictionary

       Return System.Web.HttpContext.Current.Application.StaticObjects("ConnLib")

   End Function

End Class

# re: The CodeExpressionBuilder

Friday, October 26, 2007 2:54 PM by Patty

Turns out it was a security thing because I was working on a UNC share.  I had to use caspol.exe to grant the share full trust.  Now the code expression is recognized in VS2005 as well as when I run the site.

Thanks!

# re: The CodeExpressionBuilder

Thursday, December 20, 2007 12:59 PM by Seb

Love the idea. Works great by itself. However,  I am trying to concatenate to the expression builder another string:

I have my appSettings:

<add key="rootPath" value="MyPage/"/>

now in my control I am trying to use it in a style :

Style="background-image: url(<%$Appsettings:rootPath %>Images/bg.jpg);"

However, I noticed that you cannot concatenate the Expression with the Images/bg.jpg.

Is there a way around ?

# re: The CodeExpressionBuilder

Thursday, December 20, 2007 2:21 PM by InfinitiesLoop

Seb -- not with the AppSettings expression builder. If you used the CodeExpressionBuilder you could do it:

Style='<%$ Code: "background-image: url(" + GetSetting() + "Images/bg.jpg)"'

GetSetting is just pseudo code.

# re: The CodeExpressionBuilder

Friday, February 29, 2008 4:51 AM by manickavalli

how to assign the filename in linkbutton in asp.net using vb.net

# re: The CodeExpressionBuilder

Wednesday, March 19, 2008 6:53 PM by johny

I want to place a button on my master page, and store it's PostBackUrl in each of the slave pages.

Does the expression builder support a page-level prefix, rather than 'application' prefix? How would I store the variable in the slave page?

Alternatively, I could put the NextUrl property in a HiddenField in my slave page. But how do I reference a hidden field in the asp:button?

Is there any other way?

I'm currently achieving this with a page-load event on the slave pages, but i'd prefer to do it with some kind of markup or simple variable.

thanks

# re: The CodeExpressionBuilder

Wednesday, March 19, 2008 7:05 PM by InfinitiesLoop

johny -- sorry, I don't know what you mean by "store" the url on the slave pages. If you need to access the url from the 'slave' page you can put a property on the master page, or the slave page can find the control and get it directly.

# re: The CodeExpressionBuilder

Wednesday, March 19, 2008 8:40 PM by InfinitiesLoop

Johny -- Page_Load does not cause overhead. You are mistaking it for some kind of client-to-server operation. It's not, its just something that fires while the page is going through its normal life cycle. That method fires before the server is done processing the request. I think you think it means when the page is loaded on the client, but thats not the case. There is no server-side event for that. In fact, even Page_*UN*Load occurs before there's even a single html element displaying in the browser window.

Declaring a variable like you show isn't going to help at all. You have to understand that pages and master pages are compiled into their own classes. Declaring a variable isnt the same as it is in classic ASP or other procedural server side technology, its not a global page level variable at all.

Your Page_Load solution is fine. But I would change it so that code is within an override to Render, so it doesn't bloat your viewstate. That or just disable ViewState on the button.

# re: The CodeExpressionBuilder

Wednesday, March 19, 2008 9:21 PM by johny

ok, fair enough, thanks. but, i'd love to know:

--how can an asp:button can get a code-behind variable in it's PostBackUrl?

--how can i declare a custom page property, as you mentioned? in the page tag?

--how can an asp:button reference a page property in it's PostBackUrl?

--can an aspx page contain cofig tags, like the web.config file?

--can i declare an expression on an aspx page? how would an asp:button reference it?

MANY THANKS

# re: The CodeExpressionBuilder

Tuesday, March 25, 2008 2:43 AM by Khaled Musaied

Excellent Code , your are a King of Development

# re: The CodeExpressionBuilder

Monday, April 14, 2008 6:57 AM by sweety

Hi,

I have tried your code.It runs properly.

Now I want the data from the database.

Suppose I am having the datalist control in which I am having some controls like imagebutton,labels ,textboxes,etc.Now I want to show the data on my page from database by binding the datalist from database.

Can You please tell me how do I use the expression builders from database.

Thanks

It's urgent

# re: The CodeExpressionBuilder

Monday, April 14, 2008 1:51 PM by InfinitiesLoop

The code expression is not special, it's just code. How you access your database depends on your project, the database, if you have an object model, etc etc. Using an expression like this for database access isn't what I recommend, for that you should probably be using databinding and the data source controls. Search for SqlDataSource or ObjectDataSource for plenty of literature on how to use them.

# re: The CodeExpressionBuilder

Tuesday, April 15, 2008 6:35 AM by sweety

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

   {

       DbProvider getContent = new DbProvider();

       subContent = getContent.getcontenttext();

       //while (subContent.Read())

           return new CodeSnippetExpression(entry.Expression);  

   }

public SqlDataReader getcontenttext()

       {

            SqlParameter[] sqlParam = new SqlParameter[1];

            SqlDataReader subContent;

            //sqlParam[0] = new SqlParameter("@contentid", SqlDbType.Int);

            //sqlParam[0].Value = entry;

            //sqlParam[0].Size = 4;

            initializeDBConnection();

            subContent = execSelectByKey("Select.Content");

            return subContent;

       }

and following is my query

select contenttext from ContentManagement where contentid=1

what exactly  return new CodeSnippetExpression(entry.Expression);   statement returns and what value is displayed by entry.Expression.

Now this "1" I am passing to <%$ My: 1%> in the <td>.

I am returning this query as sqldatareader.

Now I want to show the data where it is returning the entry.Expression i.e 1.

if I write

while (dr.read)

{

  return new CodeSnippetExpression(entry.Expression);

}

it gives me an error : no all code returns a value.

So, how should I display and write the query where the id is 1 in the databse which is I am passing to <%$ My: 1%>.

Please help me

It' s urgent

# re: The CodeExpressionBuilder

Tuesday, April 15, 2008 12:49 PM by InfinitiesLoop

sweety -- you are barking up the wrong tree completely. Expression builders are NOT for database access. I suggest you follow my previous advice and read up on using the SqlDataSource control and the databound controls in ASP.NET.

# re: The CodeExpressionBuilder

Wednesday, April 23, 2008 3:40 PM by aldo

Thank you. Very usefull article

# re: The CodeExpressionBuilder

Monday, May 12, 2008 4:27 PM by scubaSteve

Do you have a VB.NET example.  I've been trying to translate your example without success.  Also, <expressionbuilders> is not valid in my web.config file.  Should the class below be in a specific folder?

Thx!

<Compilation.ExpressionPrefix("Code")> _

Public Class CodeExpressionBuilder

   Inherits System.Web.Compilation.ExpressionBuilder

   Public Overrides Function ParseExpression(ByVal expression As String, ByVal propertyType As Type, ByVal context As System.Web.Compilation.ExpressionBuilderContext) As Object

       Return expression

   End Function 'ParseExpression

   Public Overrides Function GetCodeExpression(ByVal entry As BoundPropertyEntry, ByVal parsedData As Object, ByVal context As System.Web.Compilation.ExpressionBuilderContext) As CodeExpression

       Return New CodeSnippetExpression(parsedData.ToString())

   End Function 'GetCodeExpression

End Class 'CodeExpressionBuilder

# re: The CodeExpressionBuilder

Tuesday, May 13, 2008 2:26 PM by Dave

I've run into a situation that seems very related to this article, but ultimately I can't find a solution. I'm using ASP.NET 2.0 w/ c#.

I have 2 repeaters. A top repeater and a bottom one. The bottom one contains buttons and textboxes. In my app, if one of those buttons is clicked or the textbox is changed, content in both the top and bottom repeater is supposed to change.  The button fires the OnCommand event and the textbox fires the TextChanged event. I've noticed the following behavior:

1) If you use <%= to dynamically display information in the top repeater, the content in the top repeater updates.

2) If you use <%# to dynamically display information in the top repeater, the content in the top repeater does NOT update! This is a killer for my app!  I'm about to to move this to the Page_Load event.

To be more specific (and maybe this is the bug), I'm actually calling a method in my code behind (I have to) in both #1 and #2. I'd love to use ExpressionBuilder, but I need some data from the Container.DataItem object (the local variable created only for <%# syntax).

To me, this is a shortcoming of .NET and I've been trying to research it and haven't heard anyone else getting this issue. This is the closest article I've found.

# re: The CodeExpressionBuilder

Tuesday, May 13, 2008 4:03 PM by scubaSteve

figured it out...

needed:

Imports System.CodeDom

Imports System.Web

<Compilation.ExpressionPrefix("Code")> _

Public Class CodeExpressionBuilder

   Inherits Compilation.ExpressionBuilder

   Public Overloads Overrides Function GetCodeExpression(ByVal entry As BoundPropertyEntry, ByVal parsedData As Object, ByVal context As Compilation.ExpressionBuilderContext) As CodeExpression

       Return New CodeSnippetExpression(entry.Expression)

   End Function

End Class

in web.config:

<compilation debug="true" strict="false" explicit="true">

<expressionBuilders>

<add expressionPrefix="Code" type="eCGP.CodeExpressionBuilder"/>

</expressionBuilders>

</compilation>

Thanks for the cool code!

# re: The CodeExpressionBuilder

Saturday, May 24, 2008 11:13 AM by João Rollo de Sá

Man! you Really Rock!

Thanks a lot! for some other good advice on, dynamic coding in ASP .NET 2

Cheers

# re: The CodeExpressionBuilder

Friday, July 25, 2008 6:28 PM by Rex the Strange

This is beyond cool. However, heed the comments and be nice and post a VB version in future. That way those of us who speak English instead of gobbledigook can understand it.

Here is my VB version:

<expressionprefix ("code")> _

public class code_expression

 inherits expressionbuilder

 public overrides function getcodeexpression

   (entry as boundpropertyentry, _

    parseddata as object, _

    context as expressionbuildercontext) as codeexpression

     return new codesnippetexpression (entry.expression)

 end function 'getcodeexpression

end class 'code_expression

And in action (I needed to use an enum in my tags):

<custom tab_button button_id='<%$ code:buttons.home %>' />

rts

# re: The CodeExpressionBuilder

Monday, August 25, 2008 9:27 AM by alexmanfree

perfect whole day spent but the true way is found. Thank you very much.

# re: The CodeExpressionBuilder

Wednesday, August 27, 2008 6:48 PM by jbrook

Great post.  Used it for custom connectionString in SqlDataSource!

# re: The CodeExpressionBuilder

Saturday, September 13, 2008 8:26 AM by Michael Paladino

More than 2 years later and this post is still helpful.  Thanks for making my life just a bit easier!

# re: The CodeExpressionBuilder

Wednesday, September 17, 2008 4:34 AM by snomag

This post's really helpful, thanks for it, you just solved one of my problems, in an elegant way :)

# re: The CodeExpressionBuilder

Thursday, October 9, 2008 5:03 PM by ecards

Great article in usefulness and insight into .NET features.

However first rule of .net articles is include namespaces in .net articles :).

For completeness you will need at minimum these 3 for the sample code:

using System.Web.Compilation;

using System.Web.UI;

using System.CodeDom;

# re: The CodeExpressionBuilder

Saturday, December 6, 2008 9:48 AM by Marcel Popescu

Thank you... I spent a couple of hours on this before I found your page... you're a lifesaver.

# re: The CodeExpressionBuilder

Tuesday, January 27, 2009 2:53 PM by k

Would you expect multiple calls to the same code snippet to return the same results on a single page load?

Say for a simple example you called new guid in a for loop:

<asp:Literal runat="server" Text="<%$ Code: Guid.NewGuid().ToString()%>" />

This returns the same guid multiple times (for a single page load). Each new page load gives a new (duplicated) guid.

# re: The CodeExpressionBuilder

Tuesday, January 27, 2009 3:01 PM by k

I was actually trying to use the code expr builder to dump the contents of a list on an asp .net page into a server control and cant figure out how i could do that.

For example I would like all the entries in the array 'aa' to be sent to the server control:

<% string[] aa = new string[]{"a","b"};

foreach(string item in aa) { %>

<asp:Literal runat="server" Text="<%$ Code: IReallyWantTheItemValueHere%>" />

<% } %>

Any ideas on how to do this?

# re: The CodeExpressionBuilder

Tuesday, June 2, 2009 7:00 AM by Grimace of Despair

omfg... I can't believe I haven't found this blog post before! I've always abused DataBinding with some AutoBind workaround for this. Finally, I can unbind my views from my codebehind where necessary!

Tnx a lot (after more than 2 years)

# re: The CodeExpressionBuilder

Sunday, November 8, 2009 4:19 PM by Shay

Thank you, Great code!

# re: The CodeExpressionBuilder

Wednesday, November 18, 2009 4:11 AM by Paolo

Hi - your code works great! Thanks a lot.

Just one question though. If I try and use it in a user control of my own, for example:

<myControl:showSomeTest ID="idShowText" text="<%$Code: ApplicationCoreAPI.GetLocaleDescription(37)%>" runat="server" />

All that control does is take an id and gets text that corresponds to the id and returns it.

But when that is rendered, it display:

<div><%$Code: ApplicationCoreAPI.GetLocaleDescription(37)%></div>

Any way to get the ExpressionBuilder to work the same for User Controls??

Thanks

# re: The CodeExpressionBuilder

Wednesday, January 13, 2010 11:45 AM by Benton

And a BIG thank you that is. Your great post solved a big issue for me.. now it is so easy to make ASP.NET controls visible or invisible declaratively, depending on the logged user attributes which are stored in a session object. Again , sincere thanks.

# re: The CodeExpressionBuilder

Monday, February 1, 2010 10:07 PM by gary

Is there a way to get back the expression on the control's property in code behind. If yes, what the method would require as parameters?

Please help.

# re: The CodeExpressionBuilder

Monday, February 1, 2010 10:15 PM by gauravbangia

Is there a way to retrieve the expression back in code behind?

# re: The CodeExpressionBuilder

Monday, February 1, 2010 11:35 PM by InfinitiesLoop

gary -- no. The expression is translated into code injected into a dynamic class, then forgotten. Why would you need that ability?

# re: The CodeExpressionBuilder

Tuesday, February 2, 2010 7:12 PM by gary

I am providing ability to users to change the text of static label's on screen by means of my custom control. All text choices are coming from database.

In order to complete the functionality, I have to update specific record in database. This can be done only if I am aware of the expression set originally in code behind.

I was prefering to avoid burden of additional property to store the same info.

But thanks for your reply.

I was pushing myself hard to have some means of conversion to BoundPropertyEntry object. No luck yet :)

After reading your reply, I would probably pick my other option.

Thanks again.

# re: The CodeExpressionBuilder

Monday, April 19, 2010 7:42 AM by DnshPly9

There are some articles that help you realize the power of ASP.NET.

This is one example.

Thank you.....for such a Nice one...:)

# re: The CodeExpressionBuilder

Wednesday, April 21, 2010 5:20 PM by InfinitiesLoop

@MikeB: Expressions have to take the entire attribute value. So rather than this:

foo="abc<%$ Code: ... %>xyz"

You do this:

foo='<%$ Code: "abc" + ... + "xyz" %>'

(note the use of single quotes around the whole value, so as to not confuse the parser since the value contains double quotes)

# re: The CodeExpressionBuilder

Thursday, July 8, 2010 9:33 AM by ck

Worth mentioning is that the code will be evaluated just after creating control, so using getter of page property, that will be set e.g. in PageLoad event, will be unsuccessful.

But one can "inject" some more code by the ExpressionBuilder, to force setting the property one more time during chosen page event, e.g. during PreRender:

string expr = string.Format("new Func<string>(() => {{this.PreRender += (_s, _e) => @__ctrl.{0} = {1}; return {1};}})()", entry.Name, entry.Expression);

return new CodeSnippetExpression(expr);

# re: The CodeExpressionBuilder

Monday, August 2, 2010 10:09 AM by Ian Devlin

For those looking for a VB.NET version (as I was):

   <ExpressionPrefix("Code")> Public Class CodeExpressionBuilder

       Inherits ExpressionBuilder

       Public Overrides Function GetCodeExpression(ByVal entry As System.Web.UI.BoundPropertyEntry, ByVal parsedData As Object, ByVal context As System.Web.Compilation.ExpressionBuilderContext) As System.CodeDom.CodeExpression

           Return New CodeDom.CodeSnippetExpression(entry.Expression)

       End Function

   End Class

# re: The CodeExpressionBuilder

Wednesday, August 25, 2010 9:01 PM by Tobias Christiani

Hello.

Thanks for the useful post.

Is there any easy way to add "using statements" to the environment in which the expression is evaluated? Only fully qualified names seem to work for me.