发表于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