Asp.net根据形参自动获取提交数据
在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提取值!
详细代码:
:::: {#highlighter_795673 .syntaxhighlighter .csharp} ::: toolbar ?{.toolbar_item .command_help .help} :::
+--------------------------------------+---------------------------------------------------------------------------------+
| ::: {.line .number1 .index0 .alt2} | :::::::::::::::::::::::::::::::::::::::: container |
| 1 | ::: {.line .number1 .index0 .alt2} |
| ::: |
{.csharp .spaces}MethodInfo m = GetMethod(action, type);
{.csharp |
| | .plain}//获取方法信息
{.csharp .comments} |
| ::: {.line .number2 .index1 .alt1} | ::: |
| 2 | |
| ::: | ::: {.line .number2 .index1 .alt1} |
| |
{.csharp .spaces}ParameterInfo[] info = m.GetParameters();
{.csharp |
| ::: {.line .number3 .index2 .alt2} | .plain}//获取参数列表
{.csharp .comments} |
| 3 | ::: |
| ::: | |
| | ::: {.line .number3 .index2 .alt2} |
| ::: {.line .number4 .index3 .alt1} |
{.csharp .spaces}NameValueCollection collection;
{.csharp .plain} |
| 4 | ::: |
| ::: | |
| | ::: {.line .number4 .index3 .alt1} |
| ::: {.line .number5 .index4 .alt2} |
{.csharp .spaces}if
{.csharp |
| 5 | .keyword} (Request.HttpMethod.ToUpper() ==
{.csharp .plain}"POST"
{.csharp |
| ::: | .string})
{.csharp .plain} |
| | ::: |
| ::: {.line .number6 .index5 .alt1} | |
| 6 | ::: {.line .number5 .index4 .alt2} |
| ::: |
{.csharp .spaces}{
{.csharp .plain} |
| | ::: |
| ::: {.line .number7 .index6 .alt2} | |
| 7 | ::: {.line .number6 .index5 .alt1} |
| ::: |
{.csharp .spaces}collection = Request.Form;
{.csharp |
| | .plain}//如果是POST请求,则从Request.Form取值
{.csharp .comments} |
| ::: {.line .number8 .index7 .alt1} | ::: |
| 8 | |
| ::: | ::: {.line .number7 .index6 .alt2} |
| |
{.csharp .spaces}}
{.csharp .plain} |
| ::: {.line .number9 .index8 .alt2} | ::: |
| 9 | |
| ::: | ::: {.line .number8 .index7 .alt1} |
| |
{.csharp .spaces}else
{.csharp .keyword} |
| ::: {.line .number10 .index9 .alt1} | ::: |
| 10 | |
| ::: | ::: {.line .number9 .index8 .alt2} |
| |
{.csharp .spaces}{
{.csharp .plain} |
| ::: {.line .number11 .index10 .alt2} | ::: |
| 11 | |
| ::: | ::: {.line .number10 .index9 .alt1} |
| |
{.csharp .spaces}collection = Request.QueryString;
{.csharp |
| ::: {.line .number12 .index11 .alt1} | .plain}//GET请求的话,从Request.QueryString取值
{.csharp .comments} |
| 12 | ::: |
| ::: | |
| | ::: {.line .number11 .index10 .alt2} |
| ::: {.line .number13 .index12 .alt2} |
{.csharp .spaces}}
{.csharp .plain} |
| 13 | ::: |
| ::: | |
| | ::: {.line .number12 .index11 .alt1} |
| ::: {.line .number14 .index13 .alt1} | |
| 14 | ::: |
| ::: | |
| | ::: {.line .number13 .index12 .alt2} |
| ::: {.line .number15 .index14 .alt2} | |
| 15 | ::: |
| ::: | |
| | ::: {.line .number14 .index13 .alt1} |
| ::: {.line .number16 .index15 .alt1} |
{.csharp .spaces}object
{.csharp |
| 16 | .keyword}[] value = newobject[info.Length];
{.csharp .plain}//实参
{.csharp |
| ::: | .comments} |
| | ::: |
| ::: {.line .number17 .index16 .alt2} | |
| 17 | ::: {.line .number15 .index14 .alt2} |
| ::: |
{.csharp .spaces}for
{.csharp .keyword} (
{.csharp |
| | .plain}int
{.csharp .keyword} i = 0; i < info.Length; i++)
{.csharp .plain} |
| ::: {.line .number18 .index17 .alt1} | ::: |
| 18 | |
| ::: | ::: {.line .number16 .index15 .alt1} |
| |
{.csharp .spaces}{
{.csharp .plain} |
| ::: {.line .number19 .index18 .alt2} | ::: |
| 19 | |
| ::: | ::: {.line .number17 .index16 .alt2} |
| | |
| ::: {.line .number20 .index19 .alt1} | ::: |
| 20 | |
| ::: | ::: {.line .number18 .index17 .alt1} |
| |
{.csharp .spaces}if
{.csharp |
| ::: {.line .number21 .index20 .alt2} | .keyword} (IsSystemBaseType(info[i].ParameterType.FullName))
{.csharp |
| 21 | .plain}//此处判断是否系统基本类型
{.csharp .comments} |
| ::: | ::: |
| | |
| ::: {.line .number22 .index21 .alt1} | ::: {.line .number19 .index18 .alt2} |
| 22 |
{.csharp .spaces}{
{.csharp .plain} |
| ::: | ::: |
| | |
| ::: {.line .number23 .index22 .alt2} | ::: {.line .number20 .index19 .alt1} |
| 23 |
{.csharp .spaces}object
{.csharp |
| ::: | .keyword} val = collection[info[i].Name];
{.csharp |
| | .plain}//是基本类型,直接从集合中取值
{.csharp .comments} |
| ::: {.line .number24 .index23 .alt1} | ::: |
| 24 | |
| ::: | ::: {.line .number21 .index20 .alt2} |
| |
{.csharp .spaces}if
{.csharp .keyword} (val !=
{.csharp |
| ::: {.line .number25 .index24 .alt2} | .plain}null
{.csharp .keyword})
{.csharp .plain}//参数不为空
{.csharp |
| 25 | .comments} |
| ::: | ::: |
| | |
| ::: {.line .number26 .index25 .alt1} | ::: {.line .number22 .index21 .alt1} |
| 26 |
{.csharp .spaces}{
{.csharp .plain} |
| ::: | ::: |
| | |
| ::: {.line .number27 .index26 .alt2} | ::: {.line .number23 .index22 .alt2} |
| 27 |
{.csharp |
| ::: | .spaces}value[i] = Convert.ChangeType(val, info[i].ParameterType);
{.csharp |
| | .plain}//进行类型转换
{.csharp .comments} |
| ::: {.line .number28 .index27 .alt1} | ::: |
| 28 | |
| ::: | ::: {.line .number24 .index23 .alt1} |
| |
{.csharp .spaces}}
{.csharp .plain} |
| ::: {.line .number29 .index28 .alt2} | ::: |
| 29 | |
| ::: | ::: {.line .number25 .index24 .alt2} |
| |
{.csharp .spaces}else
{.csharp .keyword} |
| ::: {.line .number30 .index29 .alt1} | ::: |
| 30 | |
| ::: | ::: {.line .number26 .index25 .alt1} |
| |
{.csharp .spaces}{
{.csharp .plain} |
| ::: {.line .number31 .index30 .alt2} | ::: |
| 31 | |
| ::: | ::: {.line .number27 .index26 .alt2} |
| |
{.csharp |
| ::: {.line .number32 .index31 .alt1} | .spaces}value[i] = info[i].DefaultValue;
{.csharp |
| 32 | .plain}//参数为空,则取默认值
{.csharp .comments} |
| ::: | ::: |
| | |
| ::: {.line .number33 .index32 .alt2} | ::: {.line .number28 .index27 .alt1} |
| 33 |
{.csharp .spaces}}
{.csharp .plain} |
| ::: | ::: |
| | |
| ::: {.line .number34 .index33 .alt1} | ::: {.line .number29 .index28 .alt2} |
| 34 | |
| ::: | ::: |
| | |
| ::: {.line .number35 .index34 .alt2} | ::: {.line .number30 .index29 .alt1} |
| 35 |
{.csharp .spaces}}
{.csharp .plain} |
| ::: | ::: |
| | |
| ::: {.line .number36 .index35 .alt1} | ::: {.line .number31 .index30 .alt2} |
| 36 |
{.csharp .spaces}else
{.csharp .keyword} |
| ::: | ::: |
| | |
| ::: {.line .number37 .index36 .alt2} | ::: {.line .number32 .index31 .alt1} |
| 37 |
{.csharp .spaces}{
{.csharp .plain} |
| ::: | ::: |
| | |
| | ::: {.line .number33 .index32 .alt2} |
| |
{.csharp |
| | .spaces}value[i] = PopulateEntity(info[i].ParameterType, collection);
{.csharp |
| | .plain}//自定义实体处理,还可以判断是否数组类型
{.csharp .comments} |
| | ::: |
| | |
| | ::: {.line .number34 .index33 .alt1} |
| | |
| | ::: |
| | |
| | ::: {.line .number35 .index34 .alt2} |
| |
{.csharp .spaces}}
{.csharp .plain} |
| | ::: |
| | |
| | ::: {.line .number36 .index35 .alt1} |
| | |
| | ::: |
| | |
| | ::: {.line .number37 .index36 .alt2} |
| |
{.csharp .spaces}}
{.csharp .plain} |
| | ::: |
| | :::::::::::::::::::::::::::::::::::::::: |
+--------------------------------------+---------------------------------------------------------------------------------+
::::
自定义的实体的赋值也差不多,先通过反射获取实体的属性,再通过属性名去提取值
:::: {#highlighter_110336 .syntaxhighlighter .csharp} ::: toolbar ?{.toolbar_item .command_help .help} :::
+--------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
| ::: {.line .number1 .index0 .alt2} | :::::::::::::::::::::::::::::: container |
| 1 | ::: {.line .number1 .index0 .alt2} |
| ::: |
{.csharp .spaces}public
{.csharp .keyword} object
{.csharp |
| | .keyword} PopulateEntity(Type type, System.Collections.Specialized.NameValueCollection collection)
{.csharp .plain} |
| ::: {.line .number2 .index1 .alt1} | ::: |
| 2 | |
| ::: | ::: {.line .number2 .index1 .alt1} |
| |
{.csharp .spaces}{
{.csharp .plain} |
| ::: {.line .number3 .index2 .alt2} | ::: |
| 3 | |
| ::: | ::: {.line .number3 .index2 .alt2} |
| |
{.csharp .spaces}object
{.csharp .keyword} entity = Activator.CreateInstance(type);
{.csharp |
| ::: {.line .number4 .index3 .alt1} | .plain}//根据类型创建实例
{.csharp .comments} |
| 4 | ::: |
| ::: | |
| | ::: {.line .number4 .index3 .alt1} |
| ::: {.line .number5 .index4 .alt2} |
{.csharp .spaces}PropertyInfo[] propertys = type.GetProperties();
{.csharp .plain}//获取所有属性
{.csharp |
| 5 | .comments} |
| ::: | ::: |
| | |
| ::: {.line .number6 .index5 .alt1} | ::: {.line .number5 .index4 .alt2} |
| 6 |
{.csharp .spaces}foreach
{.csharp .keyword} (PropertyInfo item
{.csharp .plain}in
{.csharp |
| ::: | .keyword} propertys)
{.csharp .plain}//循环赋值
{.csharp .comments} |
| | ::: |
| ::: {.line .number7 .index6 .alt2} | |
| 7 | ::: {.line .number6 .index5 .alt1} |
| ::: |
{.csharp .spaces}{
{.csharp .plain} |
| | ::: |
| ::: {.line .number8 .index7 .alt1} | |
| 8 | ::: {.line .number7 .index6 .alt2} |
| ::: |
{.csharp .spaces}if
{.csharp .keyword} (IsSystemBaseType(item.PropertyType.FullName))
{.csharp .plain} |
| | ::: |
| ::: {.line .number9 .index8 .alt2} | |
| 9 | ::: {.line .number8 .index7 .alt1} |
| ::: |
{.csharp .spaces}{
{.csharp .plain} |
| | ::: |
| ::: {.line .number10 .index9 .alt1} | |
| 10 | ::: {.line .number9 .index8 .alt2} |
| ::: |
{.csharp .spaces}if
{.csharp .keyword} (collection[item.Name] !=
{.csharp .plain}null
{.csharp |
| | .keyword})
{.csharp .plain} |
| ::: {.line .number11 .index10 .alt2} | ::: |
| 11 | |
| ::: | ::: {.line .number10 .index9 .alt1} |
| |
{.csharp .spaces}{
{.csharp .plain} |
| ::: {.line .number12 .index11 .alt1} | ::: |
| 12 | |
| ::: | ::: {.line .number11 .index10 .alt2} |
| |
{.csharp .spaces}if
{.csharp .keyword} (item.PropertyType.IsValueType &&
{.csharp |
| ::: {.line .number13 .index12 .alt2} | .plain}string
{.csharp .keyword}.IsNullOrEmpty(collection[item.Name]))
{.csharp .plain}//值类型,不能为Empty
{.csharp |
| 13 | .comments} |
| ::: | ::: |
| | |
| ::: {.line .number14 .index13 .alt1} | ::: {.line .number12 .index11 .alt1} |
| 14 |
{.csharp .spaces}{
{.csharp .plain} |
| ::: | ::: |
| | |
| ::: {.line .number15 .index14 .alt2} | ::: {.line .number13 .index12 .alt2} |
| 15 | |
| ::: | ::: |
| | |
| ::: {.line .number16 .index15 .alt1} | ::: {.line .number14 .index13 .alt1} |
| 16 |
{.csharp .spaces}}
{.csharp .plain} |
| ::: | ::: |
| | |
| ::: {.line .number17 .index16 .alt2} | ::: {.line .number15 .index14 .alt2} |
| 17 |
{.csharp .spaces}else
{.csharp .keyword} |
| ::: | ::: |
| | |
| ::: {.line .number18 .index17 .alt1} | ::: {.line .number16 .index15 .alt1} |
| 18 |
{.csharp .spaces}{
{.csharp .plain} |
| ::: | ::: |
| | |
| ::: {.line .number19 .index18 .alt2} | ::: {.line .number17 .index16 .alt2} |
| 19 |
{.csharp |
| ::: | .spaces}item.SetValue(entity, Convert.ChangeType(collection[item.Name], item.PropertyType),
{.csharp .plain}null
{.csharp |
| | .keyword});
{.csharp .plain} |
| ::: {.line .number20 .index19 .alt1} | ::: |
| 20 | |
| ::: | ::: {.line .number18 .index17 .alt1} |
| |
{.csharp .spaces}}
{.csharp .plain} |
| ::: {.line .number21 .index20 .alt2} | ::: |
| 21 | |
| ::: | ::: {.line .number19 .index18 .alt2} |
| |
{.csharp .spaces}}
{.csharp .plain} |
| ::: {.line .number22 .index21 .alt1} | ::: |
| 22 | |
| ::: | ::: {.line .number20 .index19 .alt1} |
| |
{.csharp .spaces}}
{.csharp .plain} |
| ::: {.line .number23 .index22 .alt2} | ::: |
| 23 | |
| ::: | ::: {.line .number21 .index20 .alt2} |
| |
{.csharp .spaces}else
{.csharp .keyword} |
| ::: {.line .number24 .index23 .alt1} | ::: |
| 24 | |
| ::: | ::: {.line .number22 .index21 .alt1} |
| |
{.csharp .spaces}{
{.csharp .plain} |
| ::: {.line .number25 .index24 .alt2} | ::: |
| 25 | |
| ::: | ::: {.line .number23 .index22 .alt2} |
| |
{.csharp |
| ::: {.line .number26 .index25 .alt1} | .spaces}item.SetValue(entity, Convert.ChangeType(PopulateEntity(item.PropertyType, collection), item.PropertyType),
{.csharp |
| 26 | .plain}null
{.csharp .keyword});
{.csharp .plain} |
| ::: | ::: |
| | |
| ::: {.line .number27 .index26 .alt2} | ::: {.line .number24 .index23 .alt1} |
| 27 |
{.csharp .spaces}}
{.csharp .plain} |
| ::: | ::: |
| | |
| | ::: {.line .number25 .index24 .alt2} |
| |
{.csharp .spaces}}
{.csharp .plain} |
| | ::: |
| | |
| | ::: {.line .number26 .index25 .alt1} |
| |
{.csharp .spaces}return
{.csharp .keyword} entity;
{.csharp .plain} |
| | ::: |
| | |
| | ::: {.line .number27 .index26 .alt2} |
| |
{.csharp .spaces}}
{.csharp .plain} |
| | ::: |
| | :::::::::::::::::::::::::::::: |
+--------------------------------------+--------------------------------------------------------------------------------------------------------------------------------+
::::
这里面没有判断数组的处理,如果需要处理数组,只要将取出来的值使用英文逗号","分隔即可(因为浏览器提交同个参数多个值时会自动以逗号分隔)!
原理并不复杂,在Asp.Net MVC中有很多类似功能,包括整个的框架,很有多结构都很巧妙和有趣,但是真正的原理却都是很简单的!
另外喜欢.net 开发的朋友,欢迎加入本人的.net技术交流QQ群: 5089240