这篇博客真是干货,干得估计还有点“磕牙”,所以还提供视频和代码。但基础稍弱的同学,怕还是得自行补充一些基础知识——就一篇文章,确实没办法面面俱到。
缘起
我忘了是不是在园子里讲过,我命名为“截断式编程”的写法。其主要目的,就是把简单的、过滤条件、“非主干的”逻辑放在最前面。比如在ASP.NET MVC的Action中,处理POST时,我们通常都要进行服务端验证,于是我们就可以这样写:
[HttpPost] public ActionResult Send(MessageSendModel model) { #region 非截断式写法 //if (ModelState.IsValid) //{ // //假设发送了一个消息 // Response.Write("消息已经发送"); //} 截断式编程 (!ModelState.IsValid) { return View(model); } //主干程序:假设发送了一个消息 Response.Write(); ); #endregion }
View Code由于采用了这种写法,我们很快就发现了一个问题:if (!ModelState.IsValid) { return View(model); }到处都是。
是不是有点“坏味道”的感觉?你是不是想怎么“弄”它一下?
ActionFilter
首先想到的,当然就是ActionFilter了:在Action执行之前,用一个Filter进行检查,不就OK了吗?
我觉得这个想法不错,但是,但是,请注意,一定要问一个为什么!为什么别人想不到呢?——这怎么可能?!
所以,在自己动手之前,养成习惯,google/bing一下,看看别人是怎么弄的。
果不其然,找到一篇博客::Automatic ModelState validation in ASP.NET MVC ,和我的思路一模一样!\(^o^)/
而且,他想得比我更周全!看得我那个兴奋啊……
所以,这里我们得到的第一个经验:动手之前先搜一搜,不要重复造轮子。
再引申开一点,
英文 + google = 伟大的程序员。
至少在目前,以及可预见的将来,对于开发人员而言,英语非常重要,非常重要,重要性怎么强调都不为过。大家可以试一下,有没有中文的类似的博客资料等,我没去试。但根据我的经验,相比于英文资料,中文资料是非常匮乏的。
关于使用搜索引擎,很多同学觉得这是一种“可耻的行为”,但其实不然。你一定要明白:你的目的是解决问题,而不是炫技,非得把什么东西都记在脑子里,非得什么都自己写出来……算了,这话可能很多人不接受,篇幅有限,懒得说了。懂的人一点就通,不懂的人你怎么说都没用。
最简单的情形
一开始解决方案还是比较简单的。我就直接放代码了:
public class ValidateModelStateAttribute : ActionFilterAttribute { OnActionExecuting(ActionExecutingContext filterContext) { if (!viewData.ModelState.IsValid) { filterContext.Result = new ViewResult(); } } }
View Code理解的难点大概就在于为什么:return View(); 和 filterContext.Result = new ViewResult(); 是等价的。
我觉得有这个问题的根源还是没有理解“面向对象”,这一直是.NET阵营程序员所缺乏的。
一起帮的QQ群里有时候就有同学犯迷糊,聊了之后,我就明白了,他始终把return View();认为是“转到那个View页面”的意思,而没有能够理解成:这就是一个方法,返回的是一个ActionResult对象。大家能明白我的意思吧?所有的Action都是一个方法,一个返回ActionResult对象的方法,然后ASP.NET MVC框架根据这个ActionResult对象,找到相应的View进行呈现(Render)。这中间多了一个环节,但这不是“脱了裤子放屁”,是非常有必要的,而且非常“精妙”的一个架构设计。
你看,这样Filter里就可以通过给filterContext.Result赋值而达到页面呈现的效果。当然,这么做最大的好处还在于UI层的“可测试化”,这又是一个非常庞杂的话题,此处先略过。
多说一句,一定要说这一句:感谢这位同学提出问题,让我知道作为初学者,那些地方是难点。话说,我做直播这么久,要收到点反馈可真难啊!
然而,这里有一个问题
如果没有bing(话说不能google真特么的悲剧)一下,我肯定就到此为止了。然而,高手就是高手,Ben Foster想到了另外一个问题:
假设页面中需要由后台传来的数据才能正常呈现时,如何在Filter里赋值,再传递给View?