一行代码搞定你的QueryString!(原创)

导读:
  Web开发做得多了,总觉得是体力活,于是搞些代码让自己脱离无聊的Coding吧(是脱离“无聊的”Coding,不是脱离无聊的“Coding”)。
  
   初级阶段
  为每个QueryString写转换的代码,针对不同的类型,进行转换和错误处理。
  
   中级阶段
  写了一个函数,专门做转换(1.1里写的):
  /// /// Convert query string to parameter.
  ///
/// Name of query string /// Default value of query string /// If the query string is required
  private object ConvertParameter(string name, object defaultValue, bool isRequired)
   高级阶段
  昨天写的,第一次发文,大家拍砖吧:
  
  主要是用了Attribute和反射的思想,首先给变量设置HttpQueryString的属性,绑定上相应的QueryString,然后由Page基类来读取相应的QueryString信息。
  属性这么写(HttpQueryStringAttribute.cs):
  using System; namespace GooKuu.Framework.Web
  {
  /// /// Specifies a field for a query string.
  ///

  [AttributeUsage(AttributeTargets.Field)]
  public sealed class HttpQueryStringAttribute : Attribute
  {
  private string _name;
  private object _defaultValue;
  private bool _isRequired;
  /// /// Constructor. The query string must be provided.
  ///
/// Name of the query string
  public HttpQueryStringAttribute(string name)
  {
  _name = name;
  _defaultValue = null _isRequired = true }
  /// /// Constructor. If the query string is not be provided, using the default value.
  ///
/// Name of the query string /// Default value of the query string which is not provided
  public HttpQueryStringAttribute(string name, object defaultValue)
  {
  _name = name;
  _defaultValue = defaultValue;
  _isRequired = false }
  /// /// Name of the query string.
  ///

  public string Name
  {
  get { return _name; }
  }
  /// /// Default value of the query string which is not provided.
  ///

  public object DefaultValue
  {
  get { return _defaultValue; }
  }
  /// /// Indicates if the query string must be provided.
  ///

  public bool IsRequired
  {
  get { return _isRequired; }
  }
  }
  }
  页面基类是这样的(PageBase.cs):
  using System; using System.Reflection; using System.Web; using System.Web.UI; namespace GooKuu.Framework.Web
  {
  /// /// Base class of all pages.
  ///

  public class PageBase : Page
  {
  /// /// Override OnLoad method of base class.
  ///
///
  protected override void OnLoad(System.EventArgs e)
  {
  ParameterInitialize();
  base.OnLoad(e);
  }
  /// /// Initialize parameters according to query strings.
  ///

  private void ParameterInitialize()
  {
  // Get Type of current page class.
  Type type = this.GetType();
  // Get all fields of current page class.
  FieldInfo[] fields = type.GetFields();
  foreach (FieldInfo field in fields)
  {
  // Get HttpQueryStringAttribute of current field.
  HttpQueryStringAttribute attribute = (HttpQueryStringAttribute)Attribute.GetCustomAttribute(field, typeof(HttpQueryStringAttribute));
  // If has HttpQueryStringAttribute, this field is for a query string.
  if (attribute != null)
  {
  SetField(field, attribute);
  }
  }
  }
  /// /// Set field according to the HttpQueryStringAttribute.
  ///
/// The field will be set /// The attribute of current field
  private void SetField(FieldInfo field, HttpQueryStringAttribute attribute)
  {
  // The query string must be provided.
  if (attribute.IsRequired)
  {
  if (Request.QueryString[attribute.Name] != null)
  {
  SetFieldValue(field, this, attribute.Name, field.FieldType);
  }
  else {
  throw new Exception(string.Format("Query string /"{0}/" is required", attribute.Name), new NullReferenceException());
  }
  }
  // If the query string is not be provided, using the default value.
  else {
  if (attribute.DefaultValue == null || field.FieldType == attribute.DefaultValue.GetType())
  {
  if (Request.QueryString[attribute.Name] == null || Request.QueryString[attribute.Name] == string.Empty)
  {
  field.SetValue(this, attribute.DefaultValue);
  }
  else {
  SetFieldValue(field, this, attribute.Name, field.FieldType);
  }
  }
  else {
  throw new Exception(string.Format("Invalid default value of query string /"{0}/"({1})", attribute.Name, field.Name), new NullReferenceException());
  }
  }
  }
  /// /// Set the value of current field according to the query string.
  ///
/// The field will be set /// The object whose field value will be set /// The name of query string /// The type to be converted
  private void SetFieldValue(FieldInfo field, object obj, string name, Type conversionType)
  {
  try {
  // Set field value.
  field.SetValue(obj, Convert.ChangeType(Request.QueryString[name], conversionType));
  }
  catch (Exception ex)
  {
  throw new Exception(string.Format("The given value of query string /"{0}/" can not be convert to {1}", name, conversionType), ex);
  }
  }
  }
  }
  在页面里,这样写就OK了(Default.aspx.cs):
  using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using GooKuu.Framework.Web; public partial class _Default : PageBase
  {
  
  /// /// Name 是Query String的名字,"Anonymous"是缺省值。
  /// 如果没有提供这个Query String,就采用缺省值。
  ///

  [HttpQueryString("Name", "Anonymous")]
  public string name;
  /// /// UserId 是Query String的名字,不提供缺省值。
  /// 如果没有提供这个Query String或者提供的格式不正确导致转换失败,都会抛出异常。
  ///

  [HttpQueryString("UserId")]
  public int userId;
  protected void Page_Load(object sender, EventArgs e)
  {
  Response.Write(string.Format("Name is {0}
", name));
  Response.Write(string.Format("UserId is {0}
", userId));
  }
  }
  posted on 2006-01-16 11:01 Ariel Y.阅读(3042) 评论(22) 编辑 收藏引用收藏至365Key所属分类: Technology
  
  
  
   评论:
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-16 11:21 | rexsp
  // Get all fields of current page class.
  FieldInfo[] fields = type.GetFields();
  感觉没有必要把所有的栏位读出来循环,只读那些加载了自定义的Attribute的就好了吧 回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-16 11:33 | Ariel Y.
  @rexsp
  我也是这么想的,可是我不知道GetFields应该传什么参数才能得到只加载了自定义的Attribute的Field。能指教一下用哪个BindingFlags枚举吗? 回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-16 13:24 | kwklover
  提两个问题:
  1,写.net的文章,是否应该注明适用于.net2.0还是.net1.x,毕竟.net发展已经5年多了,平台版本之间具有一定差异性 ?
  2,是否应该说明这种方法有什么好处和坏处 ?
  回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-16 13:41 | Ariel Y.
  @kwklover
  谢谢你的意见,确实应该写清楚的。
  我没有注明,应该是通用的:)因为没有用到什么.net 2.0的新特性,不过我确实是在VS 2005里写的。
  好处么,应该是方便吧,减少我们的代码量,脱离一部分枯燥重复的Coding。
  坏处么,应该是性能问题吧,但是我也不知道用反射会对性能造成多大影响,有时间测试一下;这里还希望高手指点一下性能的影响。
  好多朋友说看不懂:(其实本来这篇文章就不是什么入门文章,也不是学习新知识,只是介绍我的一个思路,没有教大家写代码。所以,没有做过多解释。注释已经写的很清楚了。
  回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-16 14:15 | mkimtaehee
  不懂,未来应该要学习的。(最近到处听说动态类构造啊,反射什么的)
  我的技术还停留在WINFROM的数据库 增删改查 真觉得自己低级 汗~~~~~~~~~~~~~~~~~~~~~ 回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-16 15:23 | 午夜寻欢
  终于学习到怎么用自定义属性了!
  可我还是不太明白你这些代码要完成的功能是什么?
  难道就是简单的类型转换吗?
  有这个必要写这么长的代码吗? 回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-16 17:01 | Ariel Y.
  我这段代码可以省去以后在页面里处理Query String的代码。
  比如以前写:
  public Guid userId;
  public int count;
  public void Page_Load()
  {
  try
  {
  userId = new Guid(Request.QueryString["UserId"].ToString());
  }
  catch
  {
  throw new Exception();
  }
  if(Request.QueryString["Count"] == null || Request.QueryString["Count"].ToSTring() = string.Empty)
  {
  count = 0;
  }
  else
  {
  try
  {
  count = Convert.ToInt32(Request.QueryString["Count"].ToString());
  }
  catch
  {
  throw new Exception();
  }
  }
  }
  现在只要写:
  [HttpQueryString("UserId")]
  public Guid userId; // 这里的字段不能是private的。
  [HttpQueryString("Count", 0)]
  public int count; // 这里的字段不能是private的。
  就可以了。
  难道你只看到了类型转换?
  怎么说也是根据定义的变量的数据类型自动转换对应的QueryString吧?呵呵。
  我觉得“有这个必要写这么长的代码吗?”这种思想是很有害的一种想法。
  假设我这个代码有100行,我一次就写这么多了,以后每次就只有几行。如果不这么干(我是说,不提炼一些东西出来),你每页都要写,假设20行,你写一个项目我想也不仅仅只有5个页面吧?你看,做一个项目我就比你快:)
  就像我开头说的,做一些枯燥重复的开发是没有意义的。永远是软件工人。
  回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-16 17:47 | lee_j
  我看完楼主的代码后,发现从设计上有一个失误.PageBase类是实现代码复用的关键,而用自定义Atribute反而有画蛇添足的感觉.正如楼主所说利用反射机制令代码的效率降低.
  我想有两种方法去改进
  1.把PageBase的SetField功能移到HttpRequestStringAttribute类中;
  2.不用自动义Attribute,改成Interface.PageBase去实现Interface,而不用反射机制.
  回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-16 22:35 | 木野狐
  我认为这种实现方法过于麻烦。我的实现通常都是这样的:
  在一个公共的方法类里面这样写,
  public class Util {
  private Util() {}
  // 从 querystring 集合中安全的取得一个 string. (总是不会有 null,所以叫做 'Safe')
  public static string GetStringSafeFromQueryString(Page page, string key) {
  string value = page.Request.QueryString[key];
  return (value == null) ? string.Empty : value;
  }
  // 在上述基础上,实现几个常用类型的获取方法。
  public static int GetInt32SafeFromQueryString(Page page, string key, int defaultValue) {
  string value = GetStringSafeFromQueryString(page, key);
  int i = defaultValue;
  try {
  i = int.Parse(value);
  } catch {}
  return i;
  }
  // double 的实现
  public static double GetDoubleSafeFromQueryString(Page page,
  string key, double defaultValue) {
  string value = GetStringSafeFromQueryString(page, key);
  double d = defaultValue;
  try {
  d = double.Parse(value);
  } catch {}
  return d;
  }
  // 同理可以写出 float, ... 的实现
  }
  在我的任何页面里面,要获取 querystring 的时候,只要这样就可以了:
  比如我要获取一个 string:
  string name = Util.GetStringSafeFromQueryString(this, "name");
  if (name.Length >0) {
  // 进行正常的处理...
  } else {
  // 不处理。
  }
  获取 int:
  int id = Util.GetInt32SafeFromQueryString(this, "id", 0);
  处理 double, float 等等方法完全一样。
  我认为就一个 QueryString 的处理没必要上升到反射的高度,其实有时候反过来想想,实现的那么复杂也许会丧失一定的灵活性。比如我某个值忽然要改为从 Form 里面得到呢?从 Session 得到呢?这时候就可以比较出哪种做法更适合敏捷的适应需求。
  页面里的 QueryString 的处理,之所以大家都很痛恨手工写编码,无非是因为这么几点:
  1. 需要判断是否 == null 才敢用 .ToString(), 很不爽。稍微不注意,就会抛出异常导致页面错误。
  2. 整形,double 等值类型从 QueryString 里面获取的时候,不知道是否为合法的数值,因此 Parse 的时候总是要写重复的处理异常的代码。
  归纳一下,其实,一个页面用下列语法获取一个 QueryString 的时候,他得到的是如下东西:
  (假设用 string name = Request.QueryString["name"]; 来获取。)
  1. ...test.aspx 得到 null
  2. ...test.aspx?name= 得到 ""
  3. ...test.aspx?name=abc 得到 "abc"
  我认为 1 和 2 的情况实际上从程序处理上来讲,是没有区别的。因此判断 null 没有必要,我们每次都将 null 的值自动让他转为 string.Empty 应该是比较安全的做法。
  基于上述理由,我觉得如我上面所写的简单的工具类,就可以轻量级的解决安全的读取 QueryString 的问题。
  有不对的地方,请大家多多指教。 回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-16 23:35 | 双鱼座
  呵呵,这种方式与我从前做权限控制的方式几乎一样,用来处理QueryString的确小题大作了一点。两处缺陷:一是污染了Page类的代价太大了一点(自然木野孤的方案清洁一点);二是必须定义一个Field并且要加上自定义标签并且要与QueryString键字符串相吻合。
  我在控制权限的时候,那个自定义标签是抽象的,加在Page固有的Field上(通常是页面中静态的Control),对于不同的Control根本不同的权限采取不同的策略进行不同的处理,具有充分的可扩充性,这样污染Page类就物有所值。 回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-17 09:19 | Terrylee
  楼主的设计思想很好……
  可是为了QueryString花这么大的代价,值得吗? 回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-17 10:12 | Ariel Y.
  @各位
  有人说这方法画蛇添足,有人说麻烦有,人说污染,有人说小题大做。我的想法呢,很简单,前边已经说过,我是为了少写代码,越少越好,呵呵。让机器多干点,人少干点,没错吧?其实,我也有个前提,做的一些项目都是小系统,在局域网内运行,一个站点跑一个Xeon的Server。我何苦折磨自己去讨好Xeon呢?麻烦?谁麻烦?我们麻烦还是机器麻烦?机器麻烦?干吗不麻烦它?几个G的脑瓜天天在那儿傻着!
  对于Large-scale网站,我才不会用这个,性能即过程!
  这么多高人关注,谢谢,呵呵。下边的言语如果多有得罪,还请见谅!
  @lee_j
  第一点,我和你想的一样,但是我不会,能指点一下吗?在Attribute里可以读到被它绑定的对象吗?我没找到方法。
  第二点,没明白你的意思,Interface来做什么?但是好像对于我这篇文章就跑题了,我这篇文章叫一行代码搞定QueryString,呵呵。
  请指教!
  @木野狐
  你这类代码的思想,正是我现在用的。不过我觉得完全没有必要传那个Page进去,用HttpContext.Current.Request.QueryString[]就可以读了
  而且现在我有两种实现,一个是你这种Utility类,一种更OO的方法是自己实现一个QueryString类作为Page基类的成员,用的时候:this.QueryString.GetInt32(......);
  @双鱼座
  你的文章我很喜欢,但是先说一句得罪了!我有些出离愤怒了!
  第一,怎么就叫代价大了?怎么就小了?
  第二,必须定义一个Feild..............................。难道其他方式不用定义变量吗?其他方式不更是要写代码吗?其他方式不需要与QueryString键字符串相吻合吗?难道一行代码都不用写就让我实现吗?我可做不到:(
  为什么你的污染就值?怎么污染就不值?太主观了吧?我地孩儿也是孩儿啊,555555。
  @Terrylee &All
  其实我这篇文章讨论的问题真是芝麻绿豆大点子的事儿,纯属是玩些技术把戏,我也就是写着玩儿玩儿。但是真的写好了,并且简单好用,何乐而不用呢?
  回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-17 10:27 | 木野狐
  楼主的出发点很好,从技术的角度讲也是一种很有益的练习,不过双鱼座所说的“污染”其实只是从 OO 思想的角度来讲的,并没有任何贬低的意思啊。还望楼主不要误解了。常常我们会说“污染”一个名称空间之类的说法,其实说的不过是某个类,或者某个名称空间下干了比它应有的职责更多的事情而已,呵呵。
  关于我的回复,昨天回复完后,也贴到自己的 blog 上去了:
  http://rchen.cnblogs.com/archive/2006/01/16/318561.html
  根据 stone790809 网友的建议,我现在已经改进了做法,不再传递 Page 类作为参数了,这个跟你的建议是一致的 :)
  其实并非我不知道 HttpContext.Current.Request 这个用法,只是平常传递 Page 对象传惯了,写成了惯性而已,呵呵。
  回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-17 10:40 | Ariel Y.
  @木野狐
  哦,才发现,确实,从OO的角度讲,确实有污染,谢谢指正!
  @双鱼座
  不好意思啦。 回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-17 17:13 | zkxp
  什么是OO到处看到,汗一个先。。。 回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-17 22:55 | sema
  国外有类似思路的文章介绍,大家可以参考一下
  http://www.codeproject.com/aspnet/WebParameter.asp
  如果英文的看着累,也可以看看翻译的文章
  http://dragon.cnblogs.com/archive/2005/03/24/125160.html
  应该说这种思路还是很有意思的。但是实际对效率的影响的确需要评估。
  回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-18 00:22 | Ariel Y.
  @sema
  您的名字让我想起一句广告:“穿什么,就是什么”:)
  楼上吓我一身汗,跟我的好像!我可是干巴巴想出来的,呵呵。
  不过我喜欢这种说法:“但是实际对效率的影响的确需要评估”,而不是有些人(没有特指,请勿对号入座,真的):“效率很差,效率不高”。
  知道读数据DataReader比DataAdpater+DataSet快多少吗?总有人说快好多,实际的评测结果好像是14%-18%(参考自“DEV411 ASP.NET: Best Practices For Performance - Stephen Walther www.SuperexpertTraining.com - TechEd 2004”)
  @zhxp
  OO means Object-Oriented Programming Concepts
  回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-19 12:35 | torome
  看了高人的文章.
  自己感觉还有很多要学习。.
  努力!~ 回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-20 15:10 | Stanley Liu
  搞明白自定义属性了,happying
  谢谢Ariel Y. ~ 回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-01-23 08:59 | xiao_p
  能不能把鼠标特殊效果撤销掉了……
  实在是难受,看得时候……
  呵呵
  对于文章,就没有什么好说的了,确实不错~~
  回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-02-14 10:00 | chating
  是个好方法,但程序代码效率低. 回复
  
  # re: 一行代码搞定你的QueryString!(原创) 2006-04-21 08:13 | 生活被我强奸。。。
  呵呵。。这么一大堆我不太明白@我来这里是谢谢你的:)。。
  回复
  
  # re: 一行代码搞定你的QueryString!(原创)2006-04-21 14:33 | Ariel Y.
  谢谢。 回复
  
  
  Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1368460

本文转自
http://blog.csdn.net/jelink/archive/2006/11/05/1368460.aspx
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值