URL Related Expression Builders
Well, it has been quite a while since I talked about expression builders. If you haven’t already, I suggest you have a look at that, I think you will find interesting stuff there. Because I think this is an important topic for ASP.NET, I have two new expression builders for you:
ThemeFileUrlExpressionBuilder | Returns a file URL relative to the current theme (/App_Themes/ThemeName) |
WebResourceUrlExpressionBuilder | Returns the URL for an embedded resource file in the current or another assembly |
ThemeFileUrlExpressionBuilder may be useful when you have different themes (probably even switching them dynamically) and you want to reference a file that is relative to the current theme, without having it hardcoded.
As for WebResourceUrlExpressionBuilder, it retrieves the URL for a file included in an assembly as a web embedded resource.
As usual, the code first:
1: [ExpressionPrefix("ThemeFileUrl")]
2: public class ThemeFileUrlExpressionBuilder : ExpressionBuilder
3: {
4: public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, Object parsedData, ExpressionBuilderContext context)
5: {
6: if (String.IsNullOrEmpty(entry.Expression) == true)
7: {
8: return (new CodePrimitiveExpression(String.Empty));
9: }
10: else
11: {
12: return (new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(this.GetType()), "GetThemeUrl"), new CodePrimitiveExpression(entry.Expression)));
13: }
14: }
15:
16: public override Object EvaluateExpression(Object target, BoundPropertyEntry entry, Object parsedData, ExpressionBuilderContext context)
17: {
18: if (String.IsNullOrEmpty(entry.Expression) == true)
19: {
20: return base.EvaluateExpression(target, entry, parsedData, context);
21: }
22: else
23: {
24: return (GetThemeUrl(entry.Expression));
25: }
26: }
27:
28: public static String GetThemeUrl(String fileName)
29: {
30: Page page = HttpContext.Current.Handler as Page;
31:
32: if (page != null)
33: {
34: String path = String.Concat("/App_Themes/", page.Theme, "/", fileName);
35:
36: return (path);
37: }
38:
39: return (String.Empty);
40: }
41:
42: public override Boolean SupportsEvaluate
43: {
44: get
45: {
46: return (true);
47: }
48: }
49: }
1: [ExpressionPrefix("WebResourceUrl")]
2: public class WebResourceUrlExpressionBuilder : ExpressionBuilder
3: {
4: public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, Object parsedData, ExpressionBuilderContext context)
5: {
6: if (String.IsNullOrEmpty(entry.Expression) == true)
7: {
8: return (new CodePrimitiveExpression(String.Empty));
9: }
10: else
11: {
12: String[] parts = entry.Expression.Split(',');
13:
14: if (parts.Length == 2)
15: {
16: return (new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(this.GetType()), "GetWebResourceUrl"), new CodePrimitiveExpression(parts[0]), new CodePrimitiveExpression(parts[1])));
17: }
18: else
19: {
20: return (new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeTypeReferenceExpression(this.GetType()), "GetWebResourceUrl"), new CodePrimitiveExpression(entry.Expression)));
21: }
22: }
23: }
24:
25: public override Object ParseExpression(String expression, Type propertyType, ExpressionBuilderContext context)
26: {
27: if (String.IsNullOrEmpty(expression) == true)
28: {
29: return (base.ParseExpression(expression, propertyType, context));
30: }
31: else
32: {
33: String[] parts = expression.Split(',');
34:
35: if (parts.Length == 2)
36: {
37: return (GetWebResourceUrl(parts[0], parts[1]));
38: }
39: else
40: {
41: return (GetWebResourceUrl(expression));
42: }
43: }
44: }
45:
46: public static String GetWebResourceUrl(String resourceName)
47: {
48: Page page = HttpContext.Current.Handler as Page;
49:
50: if (page != null)
51: {
52: Type type = page.GetType();
53:
54: if (type.Namespace == "ASP")
55: {
56: type = type.BaseType;
57: }
58:
59: return (page.ClientScript.GetWebResourceUrl(type, resourceName));
60: }
61:
62: return (String.Empty);
63: }
64:
65: public static String GetWebResourceUrl(String assemblyName, String resourceName)
66: {
67: Page page = HttpContext.Current.Handler as Page;
68:
69: if (page != null)
70: {
71: Assembly asm = Assembly.Load(assemblyName);
72:
73: if (asm != null)
74: {
75: return (page.ClientScript.GetWebResourceUrl(asm.GetExportedTypes()[0], resourceName));
76: }
77: }
78:
79: return (String.Empty);
80: }
81:
82: public override Boolean SupportsEvaluate
83: {
84: get
85: {
86: return (true);
87: }
88: }
89: }
A typical usage would be:
1: <!-- this one implicitly references the current assembly -->
2: <script src='<asp:Literal runat="server" Text="<%$ WebResourceUrl:MyNamespace.SomeScript.js %>"/>1: ' type="text/javascript">1: </script>
2:
3: <!-- while this one explicitly references another assembly -->4: <script src='<asp:Literal runat="server" Text="<%$ WebResourceUrl:AnotherAssembly, AnotherNamespace.SomeOtherScript.js %>"/>' type="text/javascript"></script>
3:
4: <asp:Image runat="server" ImageUrl='<%$ ThemeFileUrl:MyThemePicture.png %>' />
5:
6:
You will have to register these expression builders on the Web.config file:
1: <system.web>
2: <compilation>
3: <expressionBuilders>
4: <add expressionPrefix="WebResourceUrl" type="MyNamespace.WebResourceUrlExpressionBuilder, MyAssembly"/>
5: <add expressionPrefix="ThemeFileUrl" type="MyNamespace.ThemeFileUrlExpressionBuilder, MyAssembly"/>
6: </expressionBuilders>
7: </compilation>
8: ...
And for the embedded resource, you mark a file (in this case, a JavaScript file) as an embedded resource, like this:
And you also have to register it with an assembly-level attribute, probably on AssemblyInfo.cs:
1: [assembly: WebResource("MyNamespace.SomeScript.js", "text/javascript")]
Of course, do replace MyNamespace and MyAssembly for your actual values. By the way, this is not specific to .NET 4, it will work from 2.0 upwards.
Looking forward to hearing from you!