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='&lt;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:

image

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! Winking smile

                             

2 Comments

  • writing poems about our baby, drawing picretus for her, releasing baloons to heaven, making blankets, hanging her hand and foot print in our home, hanging christmas ornaments with her name, painting garden rocks with her name, making birthday cakes each year on her birthday, blowing kisses to heaven when we pass the cemetery where she is buried, helping others with the loss of their babies.

  • 表示英文太菜,可否把Guy的评论也稍微翻译下。。。My version of the qiestuon starts out by restricting the input to seven letters (for Scrabble) and it was assumed you'd discard any word longer than the rack or shorter than the current best solution so a 32-bit word suffices with some finesses hinted below.Candidates who think a bitmask alone would suffice, don't understand the distinction between a bag and a set. //set俺懂,bag是啥意思?关键字眼不理解真是害死人啊。。。

Comments have been disabled for this content.