不再为频繁的QueryString解析而苦恼

 在做ASP.NET开发的时候,很多人都对频繁地解析QueryString中的值而苦恼,因为会在几乎每个页面上编写相似的代码将地址中的参数转换为相应的值。假设有一个页面用来显示文章的内容,并且需要由QueryString中的id参数提供文章的ID,请参考以下代码:

 

  1. string arg;
  2. Guid aritcleId;
  3. arg = Request.QueryString["id"];
  4. if (!String.IsNullOrEmpty(arg))
  5. {
  6.   try { articleId = new Guid(arg); }
  7.   catch { articleId = Guid.Empty; }
  8. }
  9. if (articleId != Guid.Empty)
  10. {
  11.    // 开始载入并显示文章的内容。
  12.    // ...
  13. }
  14. else
  15. {
  16.    // 向用户发出参数格式错误的警告。
  17. }

看看,仅解析一个ID就要这么多的代码,如果参数多,或者在很多页面上都要做相同的事情就会显得很麻烦。我在自己的工作过程中有这样的体会,非常不爽,为了提高工作效率,我自己写了一个类来简化这方面工作,以期望达到简化工作量和代码量的目的。先来看看使用案例,将以上代码转换为新的方式:

 

  1. // 声明一个保护级别的字段用来存放解析后的值。
  2. [QueryString("id")]
  3. protected Guid articleId;
  4. protected void Page_Load(object sender, EventArgs e)
  5. {
  6.   // 开始解析QueryString中的内容。
  7.   QueryStringAttribute.Parse();
  8.   // 此时已获取了articleId的值,接下来就是把文章内容显示出来。
  9.   // 当然还有必要对articleId的值进行有效性验证。
  10.   // ...
  11. }

两段程序相比,后者只需要声明一个字段,再有一行解析语句就可以了,简化了许多工作。假如果参数的个数多,这种差别会更明显。好了,下面说说这个QueryStringAttribute类的原理了。

其实原理并没有想象的那么复杂,简单的说,就是通过反射取出页面上定义了QueryStringAttribute的所有字段,再比对QueryStringAttribute中指定的参数名字,把字符串转换为相应的值就可以了。要取出页面上字义的字段,可以用Type.GetFields()方法先取出所有的字段,再依次检测它们是否有定义了QueryStringAttribute即可,代码如下:

 

  1. QueryStringAttribute qa;
  2. Type type = page.GetType();
  3. // 首先取出页面上定义的所有字段
  4. FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
  5. // 再通过一个循环来测试每个字段是否定义了QueryStringAttribute。
  6. foreach (FieldInfo field in fields)
  7. {
  8.   qa = (QueryStringAttribute)Attribute.GetCustomAttribute(field, typeof(QueryStringAttribute), false);
  9.   if (qa != null)
  10.   {
  11.      // 程序运行到这里说明找到了一个定义了QueryStringAttribute的字段。
  12.      // 下面的程序将会对这个字段进行处理。
  13.      // ...
  14.   }
  15. }

上面这段代码中,变量qa就是在字段上定义的QueryStringAttribute类型的实例。实例中有一个非常重要的属就,就是Name,它用来指示这个字段对应到QueryString中的哪个参数。因为在创建QueryStringAttribute对象实例的时候已经指定Name属性,因此就可以用它来找到QueryString中的参数,并赋值给字段,可参考上述第一段代码中的形式。不过有一点必须考虑的是,此时并不知道从文本转换为具体的类型需要用哪种方式,Guid可以采用上述的办法,但其它诸如int, DateTime等类型就无从下手了。这里我采用的是用System.ComponentModel.TypeConverter来转换值类型,代码如下:

 

  1. public static object ConvertType(string text, Type valueType)
  2. {
  3.     if (string.IsNullOrEmpty(text))
  4.         return null;
  5.     if (valueType == null || valueType == TypeOfString)
  6.         return text;
  7.     TypeConverter converter = TypeDescriptor.GetConverter(valueType);
  8.     if (converter == null)
  9.         throw new NotImplementedException("无法为类型" + valueType.AssemblyQualifiedName + "找到合适的类型转换器。");
  10.     object v;
  11.     if (!converter.CanConvertFrom(TypeOfString))
  12.         throw new InvalidOperationException(
  13.             string.Format("无法将文本“{0}”转换为类型{1},是否查询项名称是否正确,或者缺少类型转换器的定义。",
  14.             text, valueType.AssemblyQualifiedName));
  15.     v = converter.ConvertFromInvariantString(text);
  16.     return v;
  17. }

接下来的一项工作,就是要把转换后的值赋给相应的字段,这太简单不过了,使用FieldInfo.SetField()方法一行搞定。这样,整个QueryStringAttribute的原理就介绍完了。

使用QueryStringAttribute虽然可以简单化程序,但它也会有负面的影响和使用限制。由于采用了反射机制,就会导致程序的性能下降,这是众所周知的。另外,对于代码隐藏的ASPX页面,实际运行时的Page对象的类型不是.cs文件中定义的那个类,而是一个自动生成的派生类,因此,必须将字段声明为protected才能被反射找到。

以上只是介绍了这个功能实现的主要原理,当然为了提高QueryStringAttribute的可用性,我还增加了一些其它的特性,例如可以设置参数是否可选,当参数为必选并且没有指定参数值时,引发异常。另外在没有提供参数的情况下,还会检测是否在字段上定义了默认值等等,在这里就不一一详述。

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值