WebResource を aspx/ascx に埋め込む Expression

id:ladybug:20060316#p1 の内容を ExpressionBuilder にまとめました。

  1. ソースコードを使用したい Web Application に取り込みます。
  2. 使用したい Web Application の web.config にエントリを追加します。
  3. aspx/aspcx で設定した prefix を指定した Expression 式を記述する

例:

    <asp:Image ID="Image1" runat="server"
               ImageUrl="<%$WebResource: ImageKit, Logo.gif %>" />

と書くと、ImageKit 型を含むアセンブリの Logo.gif という埋め込みリソースを取得する WebResource URL に置き換わります。

ソースコードを使用したい Web Application に取り込み

適当なクラスライブラリにコンパイルして参照設定に加えてもいいですし、App_Code フォルダに追加するだけでも使えます。

使用したい Web Application の web.config にエントリを追加

<configuration>
    <system.web>
        <compilation debug="false">
            <expressionBuilders>
                <add expressionPrefix="WebResource"
                     type="Lx.Web.Compilation.WebResourceExpressionBuilder"/>
            </expressionBuilders>
        </compilation>
    </system.web>
</configuration>

expressionPrefix は aspx/ascx の中で記述する <%$ xxxx %> の xxxx の部分です。省略するとソースコード側に設定された値 WebResource になります。
type は ExpressionBuilder を実装したクラス名なので、この日記に記載されたソースコードを使用する場合は上記の通りです。

ソース

// code formatted by http://manoli.net/csharpformat/
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.Compilation;
using System.CodeDom;
using System.Reflection;
using System.Diagnostics;

namespace Lx.Web.Compilation
{
    /// <summary>
    /// ResourceExpressionBuilder クラスは、ページの実行時に埋め込み Web リソースを取得する URL を作成します。
    /// 埋め込み Web リソースには特定の言語またはカルチャにローカライズされた情報を含めることができません。
    /// </summary>
    [ExpressionPrefix("WebResource")]
    public class WebResourceExpressionBuilder : ExpressionBuilder
    {
        public WebResourceExpressionBuilder()
        {
        }

        /// <summary>
        /// コンパイルなしページをサポートするか
        /// </summary>
        public override bool SupportsEvaluate
        {
            // TODO: 実行時評価を実装してサポートする
            get { return false; }
        }

        /// <summary>
        /// 文字列形式の式を解析し、式を表すオブジェクトを返します。 
        /// </summary>
        public override object ParseExpression(string expression, Type propertyType, 
                ExpressionBuilderContext context)
        {
            // <%$ WebResource: TypeName, ResourceName %>
            string[] args = expression.Split(',');
            if (args.Length != 2)
            {
                throw new HttpException(
                        "引数が不正です。グローバルリソースファイル名, キー名 形式である必要があります。: " 
                        + expression);
            }
            else
            {
                try
                {
                    // TODO: リソースの存在チェックを実施し、存在しないリソースの場合にエラーとする
                    return new ResourcesEntry(args[0].Trim(), args[1].Trim());
                }
                catch (ArgumentException e)
                {
                    throw new HttpException(
                            "引数が不正です。グローバルリソースファイル名, キー名 形式である必要があります。: "
                            + expression, e);
                }
            }
        }

        public class ResourcesEntry
        {
            public ResourcesEntry(string typename, string resname)
            {
                if (string.IsNullOrEmpty(typename))
                        throw new ArgumentNullException("typename", "リソースのファイル名が指定されていません。");
                if (string.IsNullOrEmpty(resname))
                        throw new ArgumentNullException("resname", "リソースのキー名が指定されていません。");

                this.TypeName = typename;
                this.ResourceName = resname;
            }

            public readonly string TypeName;
            public readonly string ResourceName;
        }

        /// <summary>
        /// 式を表すオブジェクトをページ実行中に使用されるコードへ変換する
        /// </summary>
        public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, 
                object parsedData, ExpressionBuilderContext context)
        {
            ResourcesEntry resent = parsedData as ResourcesEntry;
            Debug.Assert(resent != null, "aye?");

            // target = this.ClientScript
            CodeExpression target = new CodePropertyReferenceExpression(
                    new CodeThisReferenceExpression(), "ClientScript");

            // target.GetWebResourceUrl(typeof(resent.TypeName), resent.ResourceName)
            return new CodeMethodInvokeExpression(
                        target,
                        "GetWebResourceUrl",
                        new CodeTypeOfExpression(resent.TypeName),
                        new CodePrimitiveExpression(resent.ResourceName));
        }
    }
}