UpdateModel方法
WebForm 对 MVC 说:能否借你的UpdateModel方法来用用?
背景
ASP.NET MVC的Controller有个很不错的方法:UpdataModel (相对应的还有TryUpdateModel)。它能够把提交的数据(Form, QueryString, RouteData)自动更新到实体,例如:
如果提交的数据键值与Customer的属性相对应,就可以实现对Customer的属性进行更新。而一般在ASP.NET WebForm中,我们可能要写上很多类似这样的语句(在实际开发中每个页面可不止两三个赋值语句):
据我所知,有不少企业早就利用反射开发出像UpdateModel的方法,基本上符合中小型项目的需要,毕竟对于由UpdateModel带来的一点性能损失,远远比不上由于没有UpdateModel而导致需要写一堆赋值语句所带来的损失。但是,绝大多数企业的程序员还是一直在写这样的赋值语句,即使已经受尽了这种类似“机器人在打字”的折磨(因为可以夸张的说,实在看不出当写这些赋值语句时需要调用人类大脑哪些神经,所以说类似“机器人在打字”,大脑处于麻木状态),或许有些程序员喜欢这样,也乐此不疲,那么我只能说“佩服”。我是一个很很很“懒惰”的人,不喜欢干些类似“重复”性的活,我总是想着法子怎么写出通用的代码去让我能够在以后可以“偷懒”,就算是写一个小小的代码生成工具也好。 刚才说过“有不少企业早就利用反射开发出像UpdateModel的方法”,遗憾的是直到现在,我都是耳闻而没有真正看到WebForm下类似MVC的UpdateModel(注:本文说提及的WebForm 和MVC 都是ASP.NET的范畴,而UpdateModel虽然实际上只是Controller里的一个方法,但本文它还作为数据绑定机制的代名词,只是不想打太多文绉绉的名称,以防自己都看不懂)。
前面已经提到,UpdateModel其本质无非是把提交的数据(NameValueCollection 类型)转化成实体,相信每个用过反射的人都知道怎么写。但是,想写好可不简单。这里的“好”是至少包含以下几点:可扩展性(是否可以通过override每个方法,或者继承某个基类或接口来实现修改数据绑定的机制),泛化(是否可以支持复杂类型的实体,例如泛型集合),健壮性等等。
UpdateModel 正式登场
说了这么多废话,其实是想引出下面的话题: 既然MVC已经有一个优秀的UpdateModel,而且它同样是ASP.NET下的好孩子,何不“借”来给WebForm用用?说借就借,MVC挺大方的,还再三叮嘱:当初没想到老兄会对我的UpdateModel感兴趣啊,所以都是写成protected internal的访问形式了,您觉得没问题就改改凑合凑合吧。于是MVC随手掏出以下的C#文件:
没有IController这个接口,Controller怎么“活”呀?没错,WebForm只是想借“UpdateModel”,可没打算背着其他多余的东西,所以凡是与UpdateModel无关的东西都被干掉了,包括Controller后面一大堆的接口。另外,还需要清除以下的东东(如果需要添加代码肯定把我累倒,幸好只是做清除动作,暗喜中…):
1. ControllerBase 去掉IController接口,当然把与之相关的Execute,ExecuteCore方法去掉,甚至去掉Initialize方法;TempData,ViewData等等都不要了(题外话:其实TempData也是挺不错的,但是WebForm什么场景下能用到呢,苦想半天脑海中也只有零零星星几个场景,暂忽略之)。
2. ControllerContext 只保留HttpContext 和 Controller
3. Controller 最惨, 几乎减掉一半重量,只剩下Binders ,ModelState 和UpdateModel, TryUpdateModel 的一堆重载方法(如果你不需要记录数据绑定错误而带来的异常,可把ModelState也请走)。
4. 其他的改动已经忘了,印象中改动较大的就是把与RouteData, ViewData 相关的东东全部请走。
万事俱备,只欠东风。谁是东风呢?其实是为了让WebForm 中调用UpdateModel的写法与MVC一致,这里“东风”就是“扩展方法”!
(经过一番测试, UpdateModel如果由空值string.Empty向数字或日期类型转化,基本上100%都是抛异常的,但这不影响Model其他属性的更新,你也可以用TryUpdateModel)
我们应该是时候写一个Hello UpdateModel 来测试一番了:
(上一篇文章里,不少朋友抱怨我的VS 的IDE样式太难看,大家先凑合看一眼,反正都是一些无关紧要的代码)
后台测试代码:
最后点击Submit按钮成功输出:Name: Bruce Lee, Age: 123
而UpdateModel的其他重载方法都可以像MVC那样正常使用,至于QueryString更新到Model的例子,有兴趣的朋友可以自己试试,这里不一一列举。
这里想引出另外一个问题: 在WebForm里,有多少人在对控件命名时是不写前缀的呢?即实际开发中,一般控件都类似这样写:“txtName”,“txtAge”, UpdateModel可以应付吗?可能有些朋友开始失望了,也有甚者可能会说:很多人都明白MVC不该用WebForm的服务端控件,那么同样WebForm也不要去想着从MVC那里借鉴什么了。暂时来说前者我非常认可,后者我可不觉得有什么不可借鉴的。如果因为这个前缀而让UpdateModel就此划上句号的话,那么就不会是我写这篇文章的初衷。
俗话说,入乡随俗。MVC的UpdateModel来到WebForm的世界就要做点变通,顺应WebForm的一贯做法。以上提到,我对好代码的其中一个观点是易于扩展。前面的代码已经被我“砍”得“惨不忍睹”了,不想再为此而大动手术,我们就来个扩展好不好?(注:并非指.Net扩展方法,大家可以理解为拓展)
ValueProviderDictionary里有一个方法PopulateDictionary,其主要作用就是把Form,QueryString等数据统一添加到内置的字典里,而作为UpdateModel的ValueProvider。聪明的你可能已经想到,由于控件ID作为字典的key, 所以只要改动此方法,在添加数据到内置字典前去掉前缀再作为key不就成功了么?因为ValueProviderDictionary是作为默认的ValueProvider, 我不想改动它,所以另外写了一个ValueProvider: PrefixableValueProvider,其意思是:支持前缀的ValueProvider。
首先定义可能出现的前缀枚举类型:1. None,2. Camel,3. Three。1 和 3 容易理解,这里说说Camel,从字面上用Camel可能不是很妥当,详细请参考。这里是指控件的前缀都是小写字母,而随后的英文单词首字母大写。例如:txtName,lblCustomer,这是多数企业使用的控件命名规范。
PrefixableValueProvider同样实现“IDictionary<string,ValueProviderResult>”接口,里面只有PopulateDictionary方法与ValueProviderDictionary不同。 对于Camel规则,因为前缀都是小写字母,所以只要找到第一个非小写字母,就从这个字母开始截取字符串作为key即可。下面给出了一个简单的实现代码,大家可以完全不用看,以免被我的低效率和考虑不周全的代码给误导。
上面的代码考虑到这样的场景:当控件ID有下面几个:“Name”, “txtName”…,如果“Name”先被加入,而当后面发现有“txtName”,那么就会移除“Name”而使用“txtName”的值;如果先发现“txtName”,而后面不管有叫“Name”的控件还是叫“Name”的查询字符串都不会覆盖前者。
除此之外,PrefixableValueProvider百分之九十九的代码都是跟ValueProviderDictionary一样。可能有人问,这不煞费苦心吗?我也想继承ValueProviderDictionary,而override它的PopulateDictionary方法呀,谁知道它原来是private的。不过等真正用于实际开发时,我肯定把private换成protected virtual,然后在PrefixableValueProvider中override它。
瞎扯的太远差点忘了说怎么使用这个PrefixableValueProvider了,其实就是要指定Controller的ValueProvider是PrefixableValueProvider就可以:
把前面例子的控件ID改成“txtName”和“txtAge”测试就可以了,这里不详细写了。
缺点
任何圣人都有缺点,何况只是一个UpdateModel。它的缺点是:
1. 由于控件ID需要与Model符合某种约束,所以在为控件命名时就不能那么“自由”了。
2. 当页面要提交的数据跟Model不是那么一一对应时,可能需要另外处理。
代码
上面的贴图可能真的由于IDE的样式和图片压缩的原因而惨不忍睹了,可以下载本文完整的源代码:UpdateModel1.0.rar
UpdateModel方法的更多相关文章
- iview Checkbox 多选框 单个的时候 如果需要change 以后进行赋值 就要用value 不要用v-modal 然后用updateModel 方法
noSuchSituationSetFalse () { this.noSuchSituationOne = false this.$refs.noSuchSituationRef.updateMod ...
- ASP.NET MVC 在控制器中接收视图表单POST过来的数据方法
方法一:通过Request.Form [HttpPost] public ActionResult Test() { string id=Reques ...
- ASP.NET MVC系列:Model
1. Model任务 Model负责通过数据库.AD(Active Directory).Web Service及其他方式获取数据,以及将用户输入的数据保存到数据库.AD.Web Service等中. ...
- [ASP.NET MVC 小牛之路]15 - Model Binding
Model Binding(模型绑定)是 MVC 框架根据 HTTP 请求数据创建 .NET 对象的一个过程.我们之前所有示例中传递给 Action 方法参数的对象都是在 Model Binding ...
- 7 天玩转 ASP.NET MVC — 第 3 天
目录 第 1 天 第 2 天 第 3 天 第 4 天 第 5 天 第 6 天 第 7 天 0. 前言 我们假定你在开始学习时已经阅读了前两天的学习内容.在第 2 天我们完成了关于显示 Employee ...
- MVC Create
本文介绍如何在MVC里往数据库中插入新的记录. 这里用到的数据表如下: Employees Step 1: 在Control文件里加入method public ActionResult Create ...
- ASP.NET MVC 入门8、ModelState与数据验证
原帖地址:http://www.cnblogs.com/QLeelulu/archive/2008/10/08/1305962.html ViewData有一个ModelState的属性,这是一个类型 ...
- MVC3 ModelBinder
1.Model Binder从哪些地方获取数据(找到数据后会停止继续寻找) MVC 框架内置默认的 Model Binder 是 DefaultModelBinder 类.当 Action Invok ...
- Asp.Net MVC 模型(使用Entity Framework创建模型类) - Part.1
这篇教程的目的是解释在创建ASP.NET MVC应用程序时,如何使用Microsoft Entity Framework来创建数据访问类.这篇教程假设你事先对Microsoft Entity Fram ...
随机推荐
- Linux以下银行乱码
更改 /etc/sysconfig/i18n 档,例如 LANG="en_US.UTF-8",xwindow它会显示英文界面. LANG="zh_CN.GB18030&q ...
- MEF初体验之二:定义组合部件和契约
组合部件 在MEF中,一个组合部件就是一个组合单元,组合部件"出口"其它组合部件需要的服务并且从其它部件"进口"需要的服务.在MEF编程模型中,为了声明组合部件 ...
- css小技巧,如何制作一个箭头符号
首先上图: 第一种方法大家可能想到了,就是用背景图片制作箭头符号,但是下面介绍的不是这种方法. 在介绍通过border制作箭头符号之前,先看下下面的css代码: <!DOCTYPE html&g ...
- 使用log4j日志-配置载入问题
1.在eclipse中,把log4j.properties放在类路径下,在项目启动时就会自己主动载入. 2.在idea中.把log4j.properties放在类路径下,可是项目启动时不能直接载入(原 ...
- C——联合体(共同体)总结
联合体的特点 1.联合体是一种结构,在这个结构中能够不同类型的成员,但同一时间仅仅能存放当中的一种. #include <stdio.h> union Demo { int a; char ...
- Cocos2d-x使用Luajit将Lua脚本编译成bytecode,启用加密
http://www.cocoachina.com/bbs/read.php?tid=205802 lua脚本进行加密,查了一下相关的资料 ,得知lua本身能够使用luac将脚本编译为字节码(byte ...
- CentOS6.5查看一port执行状态
netstat -nap | grep 22 版权声明:本文博主原创文章,博客,未经同意不得转载.
- Matlab.NET混合编程技巧之——直接调用Matlab内置函数(附源码)
原文:[原创]Matlab.NET混合编程技巧之--直接调用Matlab内置函数(附源码) 在我的上一篇文章[原创]Matlab.NET混编技巧之——找出Matlab内置函数中,已经大概的介绍了mat ...
- OCP读书笔记(21) - 题库(ExamA)
Administer ASM disk groupsBack up the recovery catalogConfigure backup settingsConfigure, Monitor Fl ...
- VMware 10设备CentOs 6.5
最近的哥哥再次看到鸟,准备安装CentOs,一看最新的版本号为6.5,这本书5.X的,稍有不同点,二话不说,呵呵~ 矿VMware版本号是10.0.1 build-1379776 首先创建一个新的虚拟 ...