It’s pretty easy to create a custom expression builder so that you can use custom expressions in your MOSS Master Pages and Page Layouts.
(Check Out The: MSDN Documentation Page)
Expression builders allow a declarative expression syntax which lets you substitute values into your page at run time. They are fantastic for referencing resources, localization, app settings, etc.
Here’s an example of an expression builder in use in the default RedirectPageLayout.aspx, it is providing the value for the name attribute:
1 |
<p><span class="kwrd"><</span><span class="html">SharePointWebControls:CssRegistration</span> <span class="attr">name</span><span class="kwrd">="<% $SPUrl:~sitecollection/Style</span></p><p><span class="kwrd"> </span><span class="kwrd">Library/~language/Core Styles/pageLayouts.css %>"</span> <span class="attr">runat</span><span class="kwrd">="server"</span><span class="kwrd">/></span></p> |
The above example uses the SPUrl expression builder, which knows how to handle the ~sitecollection and ~language keywords, and swap them out with other values before the page is processed.
So, how do you make your own? It boils down to 5 steps, and they are all easy!
- Create yourself a new c# project, and create a class that inherits from: System.Web.Compilation.ExpressionBuilder
- Add the [ExpressionPrefix("Name")] metadata to your class.
- Override the GetCodeExpression(…) function and return a CodeExpression object.
- Strong name your assembly and add it to the GAC.
- Add an entry into your web.config to call out your assembly in the ConfigurationcompilationexpressionBuilders section of the config file.
Here is a simple expression builder based on (read: stolen from) something my colleague threw together as part of a MOSS localization project (I’ll dive deeper into how we re-rolled variations in a future post!) It works similar to SPURL, it takes in a path, and replaces keywords using the switch statement. A lot of expression builders will work in this way.
First, the C# class:
1 |
<p><span class="kwrd">using</span> System;<br /><span class="kwrd">using</span> System.Collections.Generic;<br /><span class="kwrd">using</span> System.Text;<br /><span class="kwrd">using</span> System.CodeDom;<br /><span class="kwrd">using</span> System.Web.UI;<br /><span class="kwrd">using</span> System.Web.Compilation;<br /><br /><span class="kwrd">namespace</span> BlogSamples.ExpressionBuilders<br />{<br /> [ExpressionPrefix(<span class="str">"NewURL"</span>)]<br /> <span class="kwrd">public</span> <span class="kwrd">class</span> SampleUrlExpressionBuilder : ExpressionBuilder<br /> {<br /> <span class="kwrd">public</span> <span class="kwrd">override</span> CodeExpression GetCodeExpression(BoundPropertyEntry entry,</p><p> <span class="kwrd">object</span> parsedData, ExpressionBuilderContext context)</p><p><br /> {<br /> <span class="kwrd">string</span> expressionToParse = entry.Expression;<br /> <span class="kwrd">string</span>[] tokens = expressionToParse.Split(<span class="str">'/'</span>);<br /> StringBuilder builder = <span class="kwrd">new</span> StringBuilder();<br /> builder.Append(<span class="str">"""</span>);<br /> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i < tokens.Length; i++)<br /> {<br /><br /> <span class="kwrd">switch</span> (tokens[i])<br /> {<br /> <span class="kwrd">case</span> <span class="str">"~language"</span>:<br /> builder.Append(<span class="str">"/"</span>);<br /> builder.Append(<span class="str">"" + Thread.CurrentThread.CurrentCulture.Name + ""</span>);<br /> <span class="kwrd">break</span>;<br /> <span class="kwrd">case</span> <span class="str">"~sitecollection"</span>:<br /> <span class="kwrd">break</span>;<br /> <span class="kwrd">default</span>:<br /> builder.Append(<span class="str">"/"</span>);<br /> builder.Append(tokens[i]);<br /> <span class="kwrd">break</span>;<br /> }<br /> }<br /> builder.Append(<span class="str">"""</span>);<br /> entry.Expression = builder.ToString();<br /> <span class="kwrd">return</span> <span class="kwrd">new</span> CodeSnippetExpression(entry.Expression);<br /> }<br /> }<br />}</p> |
The additions to the web.config:
1 |
<p><span class="kwrd"><</span><span class="html">configuration</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">compilation</span> <span class="attr">debug</span><span class="kwrd">="true"</span> <span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">expressionBuilders</span><span class="kwrd">></span><br /> <span class="kwrd"><</span><span class="html">add</span> <span class="attr">expressionPrefix</span><span class="kwrd">="NewURL"</span> <span class="attr">type</span><span class="kwrd">="BlogSamples.ExpressionBuilders.SampleUrlExpressionBuilder, BlogSamples.ExpressionBuilders, </span></p><p><span class="kwrd">Version=1.0.0.0, Culture=neutral, PublicKeyToken=c68a54cde91f37a"</span><span class="kwrd">/></span><br /> <span class="kwrd"></</span><span class="html">expressionBuilders</span><span class="kwrd">></span><br /> <span class="kwrd"></</span><span class="html">compilation</span><span class="kwrd">></span><br /><span class="kwrd"></</span><span class="html">configuration</span><span class="kwrd">></span></p> |
And how you could use it in a page:
1 |
<span class="kwrd"><</span><span class="html">img</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">src</span><span class="kwrd">="<% $NewUrl:~sitecollection/~language/Someimage.png %>"</span> <span class="attr">alt</span><span class="kwrd">=""</span> <span class="kwrd">/></span> |
The expression builder would replace ~sitecollection and ~language per the switch statement in our class.
(Which happens to be a bit different than the MOSS built in SPURL expression builder, but this is just an example and we’ll cover why that might be useful at a later time!)
Update:
One of the comments left here mentioned that people were having trouble using this with no-compile pages. If you follow the MSDN article at the beginning of the post you’ll see that you can enable it for no-compile pages by setting an extra property and supplying an evaluation function:
1 |
<p><span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">bool</span> SupportsEvaluate<br />{<br /> get { <span class="kwrd">return</span> <span class="kwrd">true</span>; }<br />}</p><p>and implement:</p><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">object</span> EvaluateExpression(<span class="kwrd">object</span> target, BoundPropertyEntry entry) |