不再为频繁的QueryString解析而苦恼
2008-10-24 19:32
218 查看
在做ASP.NET开发的时候,很多人都对频繁地解析QueryString中的值而苦恼,因为会在几乎每个页面上编写相似的代码将地址中的参数转换为相应的值。假设有一个页面用来显示文章的内容,并且需要由QueryString中的id参数提供文章的ID,请参考以下代码:
string arg;
Guid aritcleId;
arg = Request.QueryString["id"];
if (!String.IsNullOrEmpty(arg))
{
try { articleId = new Guid(arg); }
catch { articleId = Guid.Empty; }
}
if (articleId != Guid.Empty)
{
// 开始载入并显示文章的内容。
// ...
}
else
{
// 向用户发出参数格式错误的警告。
}
看看,仅解析一个ID就要这么多的代码,如果参数多,或者在很多页面上都要做相同的事情就会显得很麻烦。我在自己的工作过程中有这样的体会,非常不爽,为了提高工作效率,我自己写了一个类来简化这方面工作,以期望达到简化工作量和代码量的目的。先来看看使用案例,将以上代码转换为新的方式:
// 声明一个保护级别的字段用来存放解析后的值。
[QueryString("id")]
protected Guid articleId;
protected void Page_Load(object sender, EventArgs e)
{
// 开始解析QueryString中的内容。
QueryStringAttribute.Parse();
// 此时已获取了articleId的值,接下来就是把文章内容显示出来。
// 当然还有必要对articleId的值进行有效性验证。
// ...
}
两段程序相比,后者只需要声明一个字段,再有一行解析语句就可以了,简化了许多工作。假如果参数的个数多,这种差别会更明显。好了,下面说说这个QueryStringAttribute类的原理了。
其实原理并没有想象的那么复杂,简单的说,就是通过反射取出页面上定义了QueryStringAttribute的所有字段,再比对QueryStringAttribute中指定的参数名字,把字符串转换为相应的值就可以了。要取出页面上字义的字段,可以用Type.GetFields()方法先取出所有的字段,再依次检测它们是否有定义了QueryStringAttribute即可,代码如下:
QueryStringAttribute qa;
Type type = page.GetType();
// 首先取出页面上定义的所有字段
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
// 再通过一个循环来测试每个字段是否定义了QueryStringAttribute。
foreach (FieldInfo field in fields)
{
qa = (QueryStringAttribute)Attribute.GetCustomAttribute(field, typeof(QueryStringAttribute), false);
if (qa != null)
{
// 程序运行到这里说明找到了一个定义了QueryStringAttribute的字段。
// 下面的程序将会对这个字段进行处理。
// ...
}
}
上面这段代码中,变量qa就是在字段上定义的QueryStringAttribute类型的实例。实例中有一个非常重要的属就,就是Name,它用来指示这个字段对应到QueryString中的哪个参数。因为在创建QueryStringAttribute对象实例的时候已经指定Name属性,因此就可以用它来找到QueryString中的参数,并赋值给字段,可参考上述第一段代码中的形式。不过有一点必须考虑的是,此时并不知道从文本转换为具体的类型需要用哪种方式,Guid可以采用上述的办法,但其它诸如int, DateTime等类型就无从下手了。这里我采用的是用System.ComponentModel.TypeConverter来转换值类型,代码如下:
public static object ConvertType(string text, Type valueType)
{
if (string.IsNullOrEmpty(text))
return null;
if (valueType == null || valueType == TypeOfString)
return text;
TypeConverter converter = TypeDescriptor.GetConverter(valueType);
if (converter == null)
throw new NotImplementedException("无法为类型" + valueType.AssemblyQualifiedName + "找到合适的类型转换器。");
object v;
if (!converter.CanConvertFrom(TypeOfString))
throw new InvalidOperationException(
string.Format("无法将文本“{0}”转换为类型{1},是否查询项名称是否正确,或者缺少类型转换器的定义。",
text, valueType.AssemblyQualifiedName));
v = converter.ConvertFromInvariantString(text);
return v;
}
接下来的一项工作,就是要把转换后的值赋给相应的字段,这太简单不过了,使用FieldInfo.SetField()方法一行搞定。这样,整个QueryStringAttribute的原理就介绍完了。
使用QueryStringAttribute虽然可以简单化程序,但它也会有负面的影响和使用限制。由于采用了反射机制,就会导致程序的性能下降,这是众所周知的。另外,对于代码隐藏的ASPX页面,实际运行时的Page对象的类型不是.cs文件中定义的那个类,而是一个自动生成的派生类,因此,必须将字段声明为protected才能被反射找到。
以上只是介绍了这个功能实现的主要原理,当然为了提高QueryStringAttribute的可用性,我还增加了一些其它的特性,例如可以设置参数是否可选,当参数为必选并且没有指定参数值时,引发异常。另外在没有提供参数的情况下,还会检测是否在字段上定义了默认值等等,在这里就不一一详述。
string arg;
Guid aritcleId;
arg = Request.QueryString["id"];
if (!String.IsNullOrEmpty(arg))
{
try { articleId = new Guid(arg); }
catch { articleId = Guid.Empty; }
}
if (articleId != Guid.Empty)
{
// 开始载入并显示文章的内容。
// ...
}
else
{
// 向用户发出参数格式错误的警告。
}
看看,仅解析一个ID就要这么多的代码,如果参数多,或者在很多页面上都要做相同的事情就会显得很麻烦。我在自己的工作过程中有这样的体会,非常不爽,为了提高工作效率,我自己写了一个类来简化这方面工作,以期望达到简化工作量和代码量的目的。先来看看使用案例,将以上代码转换为新的方式:
// 声明一个保护级别的字段用来存放解析后的值。
[QueryString("id")]
protected Guid articleId;
protected void Page_Load(object sender, EventArgs e)
{
// 开始解析QueryString中的内容。
QueryStringAttribute.Parse();
// 此时已获取了articleId的值,接下来就是把文章内容显示出来。
// 当然还有必要对articleId的值进行有效性验证。
// ...
}
两段程序相比,后者只需要声明一个字段,再有一行解析语句就可以了,简化了许多工作。假如果参数的个数多,这种差别会更明显。好了,下面说说这个QueryStringAttribute类的原理了。
其实原理并没有想象的那么复杂,简单的说,就是通过反射取出页面上定义了QueryStringAttribute的所有字段,再比对QueryStringAttribute中指定的参数名字,把字符串转换为相应的值就可以了。要取出页面上字义的字段,可以用Type.GetFields()方法先取出所有的字段,再依次检测它们是否有定义了QueryStringAttribute即可,代码如下:
QueryStringAttribute qa;
Type type = page.GetType();
// 首先取出页面上定义的所有字段
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
// 再通过一个循环来测试每个字段是否定义了QueryStringAttribute。
foreach (FieldInfo field in fields)
{
qa = (QueryStringAttribute)Attribute.GetCustomAttribute(field, typeof(QueryStringAttribute), false);
if (qa != null)
{
// 程序运行到这里说明找到了一个定义了QueryStringAttribute的字段。
// 下面的程序将会对这个字段进行处理。
// ...
}
}
上面这段代码中,变量qa就是在字段上定义的QueryStringAttribute类型的实例。实例中有一个非常重要的属就,就是Name,它用来指示这个字段对应到QueryString中的哪个参数。因为在创建QueryStringAttribute对象实例的时候已经指定Name属性,因此就可以用它来找到QueryString中的参数,并赋值给字段,可参考上述第一段代码中的形式。不过有一点必须考虑的是,此时并不知道从文本转换为具体的类型需要用哪种方式,Guid可以采用上述的办法,但其它诸如int, DateTime等类型就无从下手了。这里我采用的是用System.ComponentModel.TypeConverter来转换值类型,代码如下:
public static object ConvertType(string text, Type valueType)
{
if (string.IsNullOrEmpty(text))
return null;
if (valueType == null || valueType == TypeOfString)
return text;
TypeConverter converter = TypeDescriptor.GetConverter(valueType);
if (converter == null)
throw new NotImplementedException("无法为类型" + valueType.AssemblyQualifiedName + "找到合适的类型转换器。");
object v;
if (!converter.CanConvertFrom(TypeOfString))
throw new InvalidOperationException(
string.Format("无法将文本“{0}”转换为类型{1},是否查询项名称是否正确,或者缺少类型转换器的定义。",
text, valueType.AssemblyQualifiedName));
v = converter.ConvertFromInvariantString(text);
return v;
}
接下来的一项工作,就是要把转换后的值赋给相应的字段,这太简单不过了,使用FieldInfo.SetField()方法一行搞定。这样,整个QueryStringAttribute的原理就介绍完了。
使用QueryStringAttribute虽然可以简单化程序,但它也会有负面的影响和使用限制。由于采用了反射机制,就会导致程序的性能下降,这是众所周知的。另外,对于代码隐藏的ASPX页面,实际运行时的Page对象的类型不是.cs文件中定义的那个类,而是一个自动生成的派生类,因此,必须将字段声明为protected才能被反射找到。
以上只是介绍了这个功能实现的主要原理,当然为了提高QueryStringAttribute的可用性,我还增加了一些其它的特性,例如可以设置参数是否可选,当参数为必选并且没有指定参数值时,引发异常。另外在没有提供参数的情况下,还会检测是否在字段上定义了默认值等等,在这里就不一一详述。
相关文章推荐
- RMQ模板 求区间最大、最小值。 (前提是数组一旦确定便不再频繁更改)
- andfix实践--bug修复不再需要频繁更新版本了
- QueryString的解析
- 4项技巧使你不再为PHP中文编码苦恼
- querystring 解析url 查询字符串
- str.match(regex)与regex.exec(str)对比解析,从此不再晕
- 4项技巧使你不再为PHP中文编码苦恼
- 产品经理不再纸上谈兵——解析产品的评论排序规则
- 深入解析UTM 让企业安全不再堪忧
- Android软键盘的全面解析,让你不再怕控件被遮盖
- Everpad: 在linux(ubuntu)上最好的Evernote客户端,不再为linux没Evernote而苦恼
- Gson解析json,让json解析不再困难
- QueryString、Form表单的高效解析
- 一次dblink和硬解析频繁导致服务堵塞的排查记录
- 让32位应用程序不再为2G内存限制苦恼
- [源码]解析 SynchronousQueue 上界,下界.. 数据保存和数据传递. 堵塞队列. 有无频繁await?
- 让32位应用程序不再为2G内存限制苦恼
- debug下情况良好、release下频繁奔溃问题的跟踪与解析
- Android 软键盘的全面解析,让你不再怕控件被遮盖
- 不再为命名而苦恼!使用 MSTestEnhancer 单元测试扩展,写契约就够了