Asp.net根据形参自动获取提交数据

翅膀的初衷

发表于2013-12-22 14:26:59

  在Asp.Net MVC中定义Action时,要获取页面提交的参数,我们可以在方法内直接通过Request.QuestString或者Request.Form接收,也可以定义在形参中,尤为方便的是,我们甚至可以在形参中定义自定义类型(Model),不需要再 自己去new一个对象,然后判断是否存在数据,再一个一个的对属性进行赋值,极大的简化了广大码民的开发工作!

  此功能其实看似很神奇,其实实现原理是很简单的。大叔在这里就给大家讲一下,如何实现这样的功能!

  做这样类似的功能,我们必须用到一个.net下很强大的功能——反射,以前很多同学一听到反射,就会嚷嚷:不行不行,反射效率太低了!其实大叔说呢,这些同学一般都是要么开发才进门不久,要么呢就是本身技术功底就不杂实,就像我们老大一样,硬性规定一个可请求的地址一定要对应一个aspx页面及一个aspx.cs代码文件,他无法理解在Mvc中有些页面根本没有对应的Aspx页面的情况一样!

  反射确实会造成一定的性能损耗,但是并没有我们想象中的那么恐怖,事实上我们大多数的性能瓶颈都来源于外部IO,比如数据库!而反射带来的性能损耗,很多情况下都是可以忽略不计的, 而且我们也在不知不觉中在用着反射,比如现在的各种ORM不说,Asp.Net MVC框架本身都在大量的运用反射,就算是很老的WebForm,我们的Eval也是通过反射处理的!

  好,废话到此为止,下面直接进处正文!

  原理如下:

  1.判断请求类型,以判断数据来源,只需要考虑GET与POST即可!

  2.通过反射获取方法的形参,根据参数名去Request.QueryString或者Request.Form提取值!

  

  

  详细代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
        MethodInfo m = GetMethod(action, type);//获取方法信息
        ParameterInfo[] info = m.GetParameters();//获取参数列表
        NameValueCollection collection;
        if (Request.HttpMethod.ToUpper() == "POST")
        {
            collection = Request.Form;//如果是POST请求,则从Request.Form取值
        }
        else
        {
            collection = Request.QueryString;//GET请求的话,从Request.QueryString取值
        }
 
 
        object[] value = newobject[info.Length];//实参
        for (int i = 0; i < info.Length; i++)
        {
 
            if (IsSystemBaseType(info[i].ParameterType.FullName)) //此处判断是否系统基本类型
            {
                object val = collection[info[i].Name];//是基本类型,直接从集合中取值
                if (val != null)//参数不为空
                {
                    value[i] = Convert.ChangeType(val, info[i].ParameterType);//进行类型转换
                }
                else
                {
                    value[i] = info[i].DefaultValue;//参数为空,则取默认值
                }
 
            }
            else
            {
                value[i] = PopulateEntity(info[i].ParameterType, collection);//自定义实体处理,还可以判断是否数组类型
 
            }
 
        }

  

 

自定义的实体的赋值也差不多,先通过反射获取实体的属性,再通过属性名去提取值

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    public object PopulateEntity(Type type, System.Collections.Specialized.NameValueCollection collection)
    {
        object entity = Activator.CreateInstance(type);//根据类型创建实例
        PropertyInfo[] propertys = type.GetProperties();//获取所有属性
        foreach (PropertyInfo item in propertys)//循环赋值
        {
            if (IsSystemBaseType(item.PropertyType.FullName))
            {
                if (collection[item.Name] != null)
                {
                    if (item.PropertyType.IsValueType && string.IsNullOrEmpty(collection[item.Name])) //值类型,不能为Empty
                    {
 
                    }
                    else
                    {
                        item.SetValue(entity, Convert.ChangeType(collection[item.Name], item.PropertyType), null);
                    }
                }
            }
            else
            {
                item.SetValue(entity, Convert.ChangeType(PopulateEntity(item.PropertyType, collection), item.PropertyType), null);
            }
        }
        return entity;
    }

  这里面没有判断数组的处理,如果需要处理数组,只要将取出来的值使用英文逗号","分隔即可(因为浏览器提交同个参数多个值时会自动以逗号分隔)!

  原理并不复杂,在Asp.Net MVC中有很多类似功能,包括整个的框架,很有多结构都很巧妙和有趣,但是真正的原理却都是很简单的!

  另外喜欢.net 开发的朋友,欢迎加入本人的.net技术交流QQ群: 5089240