在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[] + ".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[])
{
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(, configuration.FilePath.LastIndexOf("\\")); string[] keys = expression.Split(','); strFile = strFile + "\\" + keys[] + ".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[] + ".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[])
{
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

Asp.Net之自定义表达式构造器(ExpressionBuilder)的更多相关文章

  1. asp.net mvc 自定义pager封装与优化

    asp.net mvc 自定义pager封装与优化 Intro 之前做了一个通用的分页组件,但是有些不足,从翻页事件和分页样式都融合在后台代码中,到翻页事件可以自定义,再到翻页和样式都和代码分离, 自 ...

  2. ASP.NET MVC 自定义路由中几个需要注意的小细节

    本文主要记录在ASP.NET MVC自定义路由时,一个需要注意的参数设置小细节. 举例来说,就是在访问 http://localhost/Home/About/arg1/arg2/arg3 这样的自定 ...

  3. Asp.net Mvc 自定义Session (二)

    在 Asp.net Mvc 自定义Session (一)中我们把数据缓存工具类写好了,今天在我们在这篇把 剩下的自定义Session写完 首先还请大家跟着我的思路一步步的来实现,既然我们要自定义Ses ...

  4. Asp.net mvc 自定义全局的错误事件HandleErrorAttribute无效

    Asp.net mvc 自定义全局的错误事件HandleErrorAttribute,结果无效, 原因: 1.没有在RegisterGlobalFilters 里面添加或者你要的位置添加. 2.你把这 ...

  5. ASP.NET之自定义异步HTTP处理程序(图文教程)

    前面我们学习了关于关于自定义同步HTTP处理程序,相信大家可能感觉有所成就,但是这种同步的机制只能对付客户访问较少的情况或者数据处理量不大的情况,而今天这篇文章就是解决同步HTTP处理程序的这个致命缺 ...

  6. asp.net core 自定义认证方式--请求头认证

    asp.net core 自定义认证方式--请求头认证 Intro 最近开始真正的实践了一些网关的东西,最近写几篇文章分享一下我的实践以及遇到的问题. 本文主要介绍网关后面的服务如何进行认证. 解决思 ...

  7. asp.net core自定义端口

    asp.net Core 自定义端口 官方文档 aspnet内库源码: https://github.com/aspnet dotnet系统内库源码:https://github.com/dotnet ...

  8. ASP.NET MVC自定义验证Authorize Attribute(包含cookie helper)

    前几天Insus.NET有在数据库实现过对某一字段进行加密码与解密<使用EncryptByPassPhrase和DecryptByPassPhrase对MS SQLServer某一字段时行加密和 ...

  9. ASP.NET MVC 自定义Razor视图WorkContext

    概述 1.在ASP.NET MVC项目开发的过程中,我们经常需要在cshtml的视图层输出一些公用信息 比如:页面Title.服务器日期时间.页面关键字.关键字描述.系统版本号.资源版本号等 2.普通 ...

随机推荐

  1. AjaxAnywhere+struts用法

    AjaxAnywhere的用法 1,简介 AjaxAnywhere被设计成能够把任何一套现存的JSP组件转换成AJAX感知组件而不需要复杂的JavaScript编码.它利用标签把Web页面简单地划分成 ...

  2. sql sever 字符串函数

    SQL Server之字符串函数   以下所有例子均Studnet表为例:  计算字符串长度len()用来计算字符串的长度 select sname ,len(sname) from student ...

  3. Nginx如何隐藏index.html

    我要隐藏目录下的index.html,修改Nginux配置如下: 1.修改文档顺序 index  index.html index.php 2.开启目录流量 在server或location 段里添加 ...

  4. C# DateTime和String转换

    "; DateTime.ParseExact(time,"yyyyMMdd",System.Globalization.DateTimeFormatInfo.Curren ...

  5. plt和got

    最近在学习linux高级调试技术.下面就动态库连接这块做了一个实验 首先理解下plt是procedure linkage table,got是global offset table.got表中存放的是 ...

  6. Windows Phone 8下 友盟社会化组件SDK的使用。

    由于项目的需要,要将友盟的社会化组件SDK由0.9更新至2.0. 版本变化比较大. 1.很多类以及命名空间已经取消了. 如UmengSocialSDK.Net.Request命名空间, UmengSo ...

  7. 动态调用web服务

    通常我们在程序中需要调用WebService时,都是通过“添加Web引用”,让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务.这样是使工作简单了,但是却和提供Web服务的URL.方法名 ...

  8. 2013长沙邀请赛A So Easy!(矩阵快速幂,共轭)

    So Easy! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  9. 利用PHP读取文件

    $fp=fopen("D:\\phpStudy\\www\\date\\file\\2.txt","r");if($fp){    while(!feof($f ...

  10. Redis学习笔记四:独立功能之发布与订阅

    客户端可以通过执行 subscribe 命令订阅一个或多个频道,每当有其他客户端向被订阅的频道发送消息时,频道所有的订阅者都会收到这条消息. 客户端还可以通过执行 psubscribe 命令订阅一个或 ...