文章出處

在Asp.Net的Page頁面中我們經常會使用到資源文件。讀取資源文件的方式為:<%$Resources:Resource1,Test1%>,這樣就可以顯示Resource1這個資源文件中的Test1的鍵值,并且在頁面設計過程中就可以正確的顯示資源文件中的值了。這里就是使用到了.Net中的表達式構造器,那么它是如何實現的?我們能不能定義自己的表達式構造器呢?本文通過構建一個簡單的Xml表達式構造器來說明這一過程。 

首先來看看Asp.Net中的表達式構造器是如何實現的
默認在C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\web.config中我們可以找到如下配置節:

 

      <expressionBuilders>
        <add expressionPrefix="Resources" type="System.Web.Compilation.ResourceExpressionBuilder"/>
        <add expressionPrefix="ConnectionStrings" type="System.Web.Compilation.ConnectionStringsExpressionBuilder"/>
        <add expressionPrefix="AppSettings" type="System.Web.Compilation.AppSettingsExpressionBuilder"/>
      </expressionBuilders>

在這里定義了三個表達式構造器:Resources,ConnectionStrings,AppSettings。因此我們可以在頁面中直接使用它們,比如可以使用<%$AppSettings:aa %>來讀取AppSettings的配置。注意這里使用的是$符號,它是讀取表達式構造器的專用標識。

接下來重點看看如何實現自己的表達式構造器
我們的目的是實現一個簡單的Xml表達式構造器,可以讀取指定xml文件中的配置信息,并且在頁面設計階段就可以看到效果。
一、修改配置
在自己的web.config中加入配置:

 

          <expressionBuilders>
            <add expressionPrefix="Xml" type="MyResource.XmlExpressionBuilder, MyResource, Version=1.0.0.0, Culture=neutral, PublicKeyToken=94a835118357b2d3"/>
          </expressionBuilders>

表示我們的表達式構造器的前綴為Xml,也就是在頁面中使用<%$Xml:.... %>的方式來讀取
我們自定義的表達式構造器類的類名為XmlExpressionBuilder,特別注意這個類所在的程序集需要使用強簽名

二、實現表達式構造器類(ExpressionBuilder)
首先我們的類需要從ExpressionBuilder繼承

public class XmlExpressionBuilder : ExpressionBuilder

實現GetCodeExpression方法,這個方法是在頁面實際運行時計算表達式的值使用的。它是用來為頁面初始化生成代碼(在允許頁面編譯時才會調用到此方法,Asp.Net在默認情況下是允許頁面編譯的):

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

        {

            if ((entry.DeclaringType == null) || (entry.PropertyInfo == null))

            {

                return new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(base.GetType()), "GetXmlKey", new CodeExpression[] { new CodePrimitiveExpression(entry.Expression.Trim()) });

            }

            return new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(base.GetType()), "GetXmlKey", new CodeExpression[] { new CodePrimitiveExpression(entry.Expression.Trim()), new CodeTypeOfExpression(entry.DeclaringType), new CodePrimitiveExpression(entry.PropertyInfo.Name) });

        }

這個方法主要就是動態的調用GetXmlKey這個自定義的方法:

      //取得Xml中的key值,為了測試,沒有考慮性能和異常的問題
        public static string GetXmlKey(string strKey)
        {
            string[] keys = strKey.Split(',');
            string strFile = HttpContext.Current.Server.MapPath("/") + keys[0] + ".xml";
            
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(strFile);
            XmlNodeList nodeList = xmlDoc.SelectSingleNode("test").ChildNodes;
            foreach (XmlNode xn in nodeList)
            {
                if (xn is XmlElement)
                {
                    if (xn.Name == keys[1])
                    {
                        return (xn as XmlElement).GetAttribute("value");
                    }
                }
            }
            return "";
        }
        public static object GetXmlKey(string key, Type targetType, string propertyName)
        {
            return GetXmlKey(key);
        }

在這里定義key值的格式為逗號分割的方式,比如在頁面中調用<%$Xml:test,test1 %>,那么傳遞過來的參數strKey=test,test1

實現EvaluateExpression和SupportsEvaluate方法,這兩個方法是在禁用頁面編譯時才會調用的,比如在頁面中設置如下:

<%@ Page Language="C#"  CodeBehind="Default.aspx.cs" Inherits="MyResource._Default" CompilationMode="Never" %>

這種情況下就會調用這兩個方法來取得表達式的值:

//返回一個值,該值指示是否可在不編譯的頁中計算表達式

        public override bool SupportsEvaluate
        {
            get
            {
                return true;
            }
        }

        //返回當前表達式的計算結果(禁用頁面編譯時 ---CompilationMode="Never" )

        public override object EvaluateExpression(object target, BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
        {
           return GetXmlKey(entry.Expression, target.GetType(), entry.PropertyInfo.Name);
        }

附測試的test.xml文件

<?xml version="1.0" encoding="GB2312"?>
<test>
  <test1 value="測試1"/>
  <test2 value="測試2" />
</test>

最后在自己的Aspx頁面中調用:

 <asp:Label ID="Label1" runat="server" Text="<%$Xml:test,test1 %>"></asp:Label>
        <br />
        <asp:Label ID="Label3" runat="server" Text="<%$Xml:test,test2 %>"></asp:Label>
        <br />

運行此頁面就可以正確的顯示test.xml中對應的值了。不過現在還有一個問題就是在頁面的設計界面不能正確的顯示test.xml中的值,因此我們還要接下來實現表達式編輯器類。

三、實現表達式編輯器類(ExpressionEditor)
首先在XmlExpressionBuilder上加入類屬性,指定使用哪個表達式編輯器類

 

[ExpressionEditor("MyResource.XmlExpressionEditor, MyResource, Version=1.0.0.0, Culture=neutral, PublicKeyToken=94a835118357b2d3"), ExpressionPrefix("Xml")]
    public class XmlExpressionBuilder : ExpressionBuilder

接下來實現自己的表達式編輯器類:XmlExpressionEditor,它必須從ExpressionEditor繼承

在我們的例子中只需要實現EvaluateExpression這個方法就可以了,它就是用來在頁面的設計階段來取得表達式的值的

 

public override object EvaluateExpression(string expression, object parseTimeData, Type propertyType, IServiceProvider serviceProvider)

        {
            if (serviceProvider != null)
            {
                IWebApplication service = (IWebApplication)serviceProvider.GetService(typeof(IWebApplication));
                if (service != null)
                {
                    System.Configuration.Configuration configuration = service.OpenWebConfiguration(true);

                    if (configuration != null)
                    {
                       string strFile = configuration.FilePath.Substring(0, configuration.FilePath.LastIndexOf("\\"));

                        string[] keys = expression.Split(',');

                        strFile = strFile + "\\" + keys[0] + ".xml";

                        return XmlExpressionBuilder.GetXmlKey(expression, strFile);
                    }
                }
            } 
            return "";

        }

在這里也是通過調用XmlExpressionBuilder類中的GetXmlKey方法的,但是由于在設計狀態下是取不到HttpContext.Current的值的,因此在這個方法中我通過IServiceProvider接口來取得當前路徑,將得到xml文件名作為參數傳遞給GetXmlKey方法。修改后的GetXmlKey方法如下:

 //取得Xml中的key值,為了測試,沒有考慮性能和異常的問題
        public static string GetXmlKey(string strKey, string strFileName)
        {
            string[] keys = strKey.Split(',');
            string strFile = "";
            if (String.IsNullOrEmpty(strFileName))
            {
                strFile = HttpContext.Current.Server.MapPath("/") + keys[0] + ".xml";
            }
            else
            {
                strFile = strFileName;
            }
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(strFile);
            XmlNodeList nodeList = xmlDoc.SelectSingleNode("test").ChildNodes;
            foreach (XmlNode xn in nodeList)
            {
                if (xn is XmlElement)
                {
                    if (xn.Name == keys[1])
                    {
                        return (xn as XmlElement).GetAttribute("value");
                    }
                }
            }
            return "";
        }
        public static object GetXmlKey(string key, Type targetType, string propertyName)
        {
            return GetXmlKey(key, "");
        }
        public static string GetXmlKey(string strKey)
        {
            return GetXmlKey(strKey, "");
        }

這樣就可以在頁面的設計視圖取得正確的值了(當修改了XmlExpressionEditor文件后,重新編譯后可能在設計視圖還是不能正確顯示,需要把VS2005重新啟動一下就可以了)

轉自:http://www.cnblogs.com/firstyi/archive/2008/08/05/1260844.html


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()