在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
文章列表