摩诘

我思故我在 常辨而常新

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  20 随笔 :: 2 文章 :: 340 评论 :: 9 Trackbacks
注:去年写的一篇文章了,现在把它贴出来,以做参考
这里是示例代码
利用反射解决
QueryStringSession中的参数绑定问题

一.     前言

本文主要译自网上的一篇文章(http://www.codeproject.com/aspnet/WebParameter.asp),自己又作了一些改进,因此形成了这篇心得。

 

二.     简介:

本文介绍了在ASP.NET页面对象中利用元数据自动从Page.Request对象的QueryString中填充页面的变量和属性的策略.

 

三.     问题的提出

当你对ASP.NET页面进行参数化时,比如:从Request.QueryStringGET)或Request.FormPOST)中获取参数,你需要花大量的时间写类似以下的代码:

protected string FirstName
{
    
get
 
{
     
return Request.QueryString["FirstName"]; 
    }

}

 


但是你必须处理潜在的
FirstNamenull值是的情况,因此你可能会通过如下的代码提供一个缺省值

protected static string IsNull(string test, string defaultValue){
    
return test==null ? defaultValue : test;
}


protected string FirstName_NullSafe{
   
getreturn IsNull(Request.QueryString["FirstName"],""); }
}

对于非字符串类型,你也可以通过稍微修改以上代码来决定当参数为null时是提供一个缺省值还是抛出一个异常,只是要用到Convert.ToXXX()函数

protected int CustomerID{
    
get          {
               
object o=Request.QueryString["CustomerID"];
               
if (o==null)//如果为空,则抛出异常
                {
                       
throw new  ApplicationException("Customer ID is required to be passed"); 
                   }
               
else
                   {
 
                   
try                          {
                                //如果不空,转换成Int32型
                            return Convert.ToInt32(o,10);
                    }
                         catch(Exception err)                         {
                           
throw new ApplicationException("Invalid CustomerID", err);
                      }

                }

       }

}

 

因此,在Page_Load函数里你可能会写如下的代码进行参数初始化

private void Page_Load(object sender, System.EventArgs e)    {
       
string o;

       
// 提供一个初始值
        FirstName2 =IsNull(Request.QueryString["FirstName"], "");

       
//确保该值不为空,否则抛出异常
        o =Request.QueryString["CustomerID"];
       
if (o==null)
           
throw new  ApplicationException("Customer ID is required to be passed");
       
else
          
try{//如果转换类型不正常,抛出异常
                CustomerID2 = Convert.ToInt32(o,10);
          }
             
catch(Exception err){
               
throw new ApplicationException("Invalid CustomerID", err);
           }


 }

小结:

当你在处理从Request.QueryStringRequest.Form读取参数时,有以下的固定模式

  • Request.QueryString ( Request.Form)中检索值,
  • 当检索的值为空时抛出异常或提供一个缺省值
  • 将检索到的值转换成合适的数据成员(field)或属性(property
  • 如果检索值不能正确转换类型,抛出一个异常或提供一个缺省值

四.     解决方案:声明性参数绑定

l         表现形式:

一个解决的方案是使用元数据(metadata),并让一些函数执行实际的工作

比如说以下形式:

 [WebParameter()]
protected string FirstName;
//如果没有提供参数,则表示查找和FirstName同名的关键字,
//即QueryString[“FirstName”],

[WebParameter(
"Last_Name")]
protected string LastName;
//表示从QueryString中查找"Last_Name"的变量值
//即QueryString[“Last_Name”]

[WebParameter(IsRequired
=true)]
protected int CustomerID;
//表示如果QueryString[“CustomerID”]返回空值,则抛出异常

可选的构造函数提供了从Request.QueryString中查找参数的关键字,IsRequired属性决定了当该参数缺失时是否抛出异常。  

 

l         思路

本解决方案的思路是,利用反射来检索到附加在变量上的元数据,然后根据该元数据的属性决定如何对变量进行存取,其存取模式采用如第2节(《问题的提出》)最后一部分小结里的模式,只是改成了由程序自动判断进行。

1、  检索元数据属性

如前所述,当先定义一个从System.Attribute派生的元数据类WebParameterAttribut


[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple=false, Inherited=true)]
public class WebParameterAttribute : Attribute
{
        
public int ParamName;

        
public string DefaultValue
        
{
            
get{    return _default    ;   }
            
set{    _default=value    ;    }
     }

}

 

注:AttributeUsageAttribute使用说明

 

说明:


[WebParameter("Last_Name")]
protected string LastName;


    当以上面形式使用自定义的属性类时,实际上等与是生成了一个和LastName的类型对象LastName.GetType()相关联的WebParameterAttribute类的对象,通过LastName.GetType()对象可以检索到WebParameter对象的一些方法成员、数据成员以及属性等;

我们可以定义WebParameterAttribute类的静态方法,WebParameterAttribute.SetValues(object target, System.Web.HttpRequest request)完成自动初始化某个页面的所有参数,该方法有两个参数target表示将被自动进行参数化的对象例如可以是某个页面对象Page);request是在某个页面对象的初始化时传来的Request对象;后面我们会详细解释SetValues方法的设计


示例如下面粗体部分所示:

public class WebParameterDemo : System.Web.UI.Page
    
{
        [WebParameter(
"txtFirstName")]
        
public string FirstName        ="field default";

        [WebParameter(
"txtLastName", DefaultValue="attribute default")]
        
public string LastName{
            
get{    return (string)ViewState["LastName"];    }
            
set{    ViewState["LastName"]=value;            }
        }


        [WebParameter (
"txtCustomerID", DefaultValue="0")]
        
public int CustomerID;

        
int TestNum;//注意该数据成员没有关联WebParameter属性

        
protected System.Web.UI.HtmlControls.HtmlInputText txtFirstName;
        
protected System.Web.UI.HtmlControls.HtmlInputText txtLastName;
        
protected System.Web.UI.HtmlControls.HtmlInputText txtCustomerID;

        
private void Page_Load(object sender, System.EventArgs e)
        
{
            WebParameterAttribute.SetValues(
this, Request);
           
//注意这里是用法
            txtFirstName.Value    =FirstName;
            txtLastName.Value    
=LastName;
            txtCustomerID.Value    
=CustomerID.ToString();
        }

    



    在上面的示例中,静态方法WebParameterAttribut.SetValues先获取this指针代表的Page对象的类型对象this.GetType(),然后用该类型对象获取Page对象的所有变量和属性的信息,即可以获得并操纵Page对象的FirstNameLastNameCustomerID,也包括TestNum。然后SetValues方法检查每个检索到的变量和属性,看有没有关联WebParameter对象,相对来说,数据成员TestNum就没有关联WebParameter对象。

SetValues检测到变量(field)或属性(property)关联有WebParameter对象时,该方法会检索和变量或属性向关联的WebParameter对象的具体属性,比如说:

[WebParameter("Last_Name")]
protected string LastName;


生成了一个WebParameter对象,并传递给构造函数一个参数”Last_Name”SetValues方法会检测出和string LastName相关联的WebParameter中包含的“Last_Name”并将其作为要在QueryString中检测的变量的名字。

 

 

 

 

l         代码解析

下面是SetValues的具体实现:

 

²        变量及属性定义

    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple=false, Inherited=true)]
    
public class WebParameterAttribute : Attribute
    
{
        
定义私有变量

        
Constructors
        

        
public string ParameterName
        
{
            
get{    return _name;    }
            
set{    _name=value;    }
            }

    
        
public string DefaultValue
        
{
            
get{    return _default    ;    }
            
set{    _default=value    ;    }
            }

    
        
public bool IsRequired
        
{
            
get{    return _isRequired;    }
            
set{    _isRequired=value;    }
           }

    
        
/// </summary>
        public bool IsDefaultUsedForInvalid
        
{
            
get{    return _isDefaultForInvalid;    }
            
set{    _isDefaultForInvalid=value;    }
        }


 

 

²        SetValues方法

request中检索特定值并设定target中指定变量和属性的值

public static void SetValues(object target, System.Web.HttpRequest request) 

{//传入的target对象可以是Page对象,request可以是Page.Request对象 

       
//获取target的类型信息 

         System.Type type    
=target.GetType(); 

  

         

         
//获取target公开的、实例化后的成员信息 

         MemberInfo[] members
= type.GetMembers(BindingFlags.Instance | 

         BindingFlags.Public
| 

        BindingFlags.NonPublic); 

       
//Instance:只对非静态的成员查找; 

       
//Public:只对具有公开访问属性的成员进行查找 

       
//在和Instance或static联用时, 

       
//必须指定NonPublic或Public,否则返回空值 

  

         
foreach(MemberInfo member in members) 

      


             
if((member is FieldInfo) || (member is PropertyInfo)) 

          
{//对变量和属性,设置其初始值 

                     SetValue(member, target, request); 

             }
 

         }
 

}
 

 

 

²        SetValue方法

根据member对象的类型是变量(Field)或属性(Property