现在,你有一个MVC架构的web项目,你要完成一个注册功能。

前台传了3个值到你的控制器,分别是账号、密码、邮箱。

如图:现在你要在控制器里面判断,账号名称、密码、邮箱不能为空,并且名称和密码不超过16位。

上面这个图只是个理想中的小例子,实际开发情况是,可能一次性要传十几个字段甚至更多。

那么在实际开发中,通常为了复用性,我们将这3个参数用一个实体类来代替。

即如下所示。

注:这一步会有个知识点,叫做模型验证,不懂的童鞋可以百度下,MVC会通过一定规则自动直接将参数反序列化成所对应的实体类,但是因为我这个示例是webapi模式的,写法略有不同,所以还要在参数前加个[FromBody]才能自动反序列化。

至于具体为什么会自动反序列化,在本篇并不是我要讲的主题,所以感兴趣的童鞋可以百度下:MVC下的ModelBinder    。

拦截层的解耦

现在,我认为把实体类验证给带到控制器里去写的这种方式有点不美,如果业务规则多的话,那么这样的验证代码就非常庞大,并且如果整个项目都采用这种验证模式,那么在我日后的维护阶段中就显得有点臃肿的感觉,实体类依赖于控制器方法去验证,我得先找到这个实体类,然后仔细想想有哪些方法用到了该实体类,又做了哪些验证判断,然后维护。

那么我能不能在控制器方法中 验证实体类这一步 给挪掉,不写到控制器的方法当中,写在另一个地方,统一进行管理,实现实体类的验证与控制器中的方法业务逻辑分除。

这种行为操作有点像httpModule,思想上就是设计模式所谓的降低耦合性了。

那么怎么做呢?

我们可以直接在实体类中加验证,如图

上面看到[Required],[StringLength],[RegularExpression]的这些叫做验证特性,是.net框架已经封装好的,它会对标注特性的字段采取验证。

[Required]限制了必须输入,[Required(ErrorMessage = "请输入用户名")]

[StringLength]限制了规定的长度,[StringLength(10, ErrorMessage = "长度不能超过10个字符")]

[Range] 限制了值的范围,[Range(0, 120, ErrorMessage = "年龄范围在0到120岁之间")]

[RegularExpression] 限制了必须满足正则表达式,[RegularExpression(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$", ErrorMessage = "请输入Email格式")]

[Compare]限制了与之对应的字段相等,[Compare("pwd", ErrorMessage = "两次密码要一致")]  //该特性标注的字段值必须与pwd字段值相等

.net也就封装了几个,这5个用的最多(当然,也可以自定义这种验证特性,对这块想深入了解的请百度:mvc ValidationAttribute)。

那么我标注了特性后如何进行判断呢?

我们看下控制器方法中的写法:

如图,用 ModelState.IsValid  这段话来对验证结果进行判定,如果实体类上的被标注的特性都满足条件的话,就为true,否则为false。

那么,因为这种模型验证是种模式,是全局的,所以应该单独拿出来在拦截层进行注册。

如图:

这段代码的意思就是:每当进入控制器方法之前,会判断这个方法的名称,如果包含的有Insert、check、update这三者的任意一个,都会进行拦截验证(对模型验证的结果进行判定),如果为false,那么就返回给客户端一个400状态码。

然后注册一下:(注册的地方只是个范例,因为我是webapi,只对http进行拦截)

model负责填写规则,验证由专门的验证人员去做,逻辑由专门的逻辑人员去写,这样就各司其职了。

不过,这才只是第一步!

(随着你日常的开发,你肯定会遇到这种情况)

user实体类,是专注于注册方法,说白了,就是为注册方法所写的,

我现在还要写个登录方法。

但是登录的时候,我不需要填写email,只需要填写账号和密码,对这两个字段进行验证。

可是我的实体类里面对email做了[Required]和[RegularExpression]验证,那么这样就导致了 如果我登录方法继续使用这个user实体类,那么肯定会报错,会返回个400验证码。

这种情况我该怎么解决?难道重新建个model?再重新给一遍规则?这还仅仅只有3个字段,万一有的表中有十几个字段,二十几个字段甚至更多怎么办?

重新建个model肯定不行,这样已经失去了   复用性、各司其职  的初衷。

求解决方案!在线等!

...

模型验证进阶:自由控制需要验证的字段

百度了一下,网上没有该方面的教程,博客园中也没找到,群里也没交流出个结果,但这种情况却经常遇到!

梳理下思路,大致有几种,第一种是用某种手段控制类中的这些验证特性,或者控制类中的属性字段,如启用或停用,但是c#不能对属性字段进行停启用,而控制类中的这些验证特性也有点天方夜谭,本身就是微软封装好的,你得反编译一下看下源码,然后重构?或者你直接不用这些框架封装好的验证特性,使用自己定义自定义验证特性,然后把控制方法都写在里面?这样太麻烦,而且违背初衷。自定义ModelBinder ?更扯淡。

一番折腾无果,那么就不能从特性本身找突破口了,这时,我把目标转移到ModelState.IsValid上,换一种思路实现。

我们发现其实现了GetEnumerator方法,于是对其进行遍历,可以获取到特性所绑定的字段属性的名称以及其状态。

因为要实现自由控制需要验证的字段,所以无论怎样实现,都只能通过 自定义特性 标注在方法体头上来实现。

而理想的最终呈现效果应该是这样的:

放图:

或者

使用方式:

如果方法头上有KeepZ特性的话,就进入自由控制验证字段状态。

[KeepZ("字段1","字段2")]  即:只对  字段1 和 字段2   进行验证

[KeepZ(false,"字段3")]  即:除了  字段3  之外,其余字段都进行验证

那么我们放下具体实现代码:

 public override void OnActionExecuting(HttpActionContext actionContext)
{
if ((actionContext.ActionDescriptor.ActionName.ToUpper().Contains("INSERT") || actionContext.ActionDescriptor.ActionName.ToUpper().Contains("CHECK") ||
actionContext.ActionDescriptor.ActionName.ToUpper().Contains("UPDATE")))
{
var ia = actionContext.ActionDescriptor.GetCustomAttributes<KeepZ>();
if (ia.Count != )
{
goto result;
}
foreach (KeyValuePair<string, ModelState> item in actionContext.ModelState.ToArray())
{
if (ia[].Modes == false)
{
foreach (string PropertysValue in ia[].Propertys)
{
if (item.Key.Contains(PropertysValue))
{
actionContext.ModelState.Remove(item.Key);
}
}
}
else
{
bool re = false;
foreach (string PropertysValue in ia[].Propertys)
{
if (item.Key.Contains(PropertysValue))
{
re = true;
}
}
if (re == false)
{
actionContext.ModelState.Remove(item.Key);
}
}
}
result: if (!actionContext.ModelState.IsValid)
{ actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState); }
}
}
/// <summary>
/// 保持
/// </summary>
public class KeepZ : Attribute
{
public string[] Propertys = null;
public bool Modes = true;
public KeepZ(params string[] Property)
{
Propertys = Property;
}
public KeepZ(bool Mode, params string[] Property)
{
Propertys = Property;
Modes = Mode;
}
}

如此一来,就不用再重建Model这样费时费力的方法了,现在MVC架构大多都用这种验证模式,但是却没有  自由选择验证字段的解决方案,每每遇到该情况,只能无奈重新建个实体类,对比之下,根本没有食得这种拦截层模型验证的精髓,只学个模子,反而弄巧成拙不成本意,所以我写了此篇和大家一起分享,加入了KeepZ来控制需要验证的字段,就是真正的实现了  可 复用  ,逻辑与拦截分层  了。

Demo虽小,但是这种情况下的解决方案,我在博客园中没找到,应该是园子里第一篇吧。

注意,BindAttribute 这个特性,是 针对赋值上的处理, 选择赋值 和 选择验证 是 两个 看似相同却截然不同的两个分支,本文是 自由控制验证拦截 ,所适用性在某些场景要比 BindAttribute 要多,当然,不介意的话, 你也可以 将 BindAttribute  带入本实例中,也是可以的, 剔除验证的时候 剔除赋值。

作者:小曾
出处:http://www.cnblogs.com/1996V/p/7423834.html 欢迎转载,但任何转载必须保留完整文章,在显要地方显示署名以及原文链接。如您有任何疑问或者授权方面的协商,请给我留言.Net交流群, QQ群:166843154 欲望与挣扎 

.Net高级进阶,WebApi和MVC进行模型验证的时候,教你如何自由控制需要进行验证的字段?的更多相关文章

  1. .Net高级进阶,教你如何构建企业模型数据拦截层,动态控制字段验证

    现在,你有一个MVC架构的web项目,你要完成一个注册功能. 前台传了3个值到你的控制器,分别是账号.密码.邮箱. 如图:现在你要在控制器里面判断,账号名称.密码.邮箱不能为空,并且名称和密码不超过1 ...

  2. Django笔记 —— 模型高级进阶

    最近在学习Django,打算玩玩网页后台方面的东西,因为一直很好奇但却没怎么接触过.Django对我来说是一个全新的内容,思路想来也是全新的,或许并不能写得很明白,所以大家就凑合着看吧- 本篇笔记(其 ...

  3. [.net 面向对象程序设计深入](6).NET MVC 6 —— 模型、视图、控制器、路由等的基本操作

    [.net 面向对象程序设计深入](6).NET MVC 6 —— 模型.视图.控制器.路由等的基本操作 1. 使用Visual Studio 2015创建Web App (1)文件>新建> ...

  4. 高级进阶DB2(第2版)——内部结构、高级管理与问题诊断

    <高级进阶DB2(第2版)——内部结构.高级管理与问题诊断> 基本信息 作者: 牛新庄    出版社:清华大学出版社 ISBN:9787302323839 上架时间:2013-7-3 出版 ...

  5. 高级进阶DB2(第2版)

    <高级进阶DB2(第2版)> 基本信息 作者: 牛新庄 出版社:清华大学出版社 ISBN:9787302323839 上架时间:2013-7-3 出版日期:2013 年7月 开本:16开 ...

  6. Django笔记 —— 模板高级进阶

    最近在学习Django,打算玩玩网页后台方面的东西,因为一直很好奇但却没怎么接触过.Django对我来说是一个全新的内容,思路想来也是全新的,或许并不能写得很明白,所以大家就凑合着看吧- 本篇笔记(其 ...

  7. 潭州学院-JavaVIP的Javascript的高级进阶-KeKe老师

    潭州学院-JavaVIP的Javascript的高级进阶-KeKe老师 讲的不错,可以学习 下面是教程的目录截图: 下载地址:http://www.fu83.cn/thread-283-1-1.htm ...

  8. C#可扩展编程之MEF学习笔记(五):MEF高级进阶

    好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...

  9. 爱上MVC~MVC4模型验证可以放在前端

    回到目录 MVC4.0推出后,在模型验证上有了一个新的改近,它支持前端验证,即在用户POST之前,如果验证失败,则Action(POST方式的)不会被执行,而直接停留在原视图,这对于用户体验是好的,它 ...

随机推荐

  1. RabbitMQ系列教程之六:远程过程调用(RPC)

    远程过程调用(Remote Proceddure call[RPC])(本实例都是使用的Net的客户端,使用C#编写)  在第二个教程中,我们学习了如何使用工作队列在多个工作实例之间分配耗时的任务.  ...

  2. 第一篇:webservice初探

    接触webservice也有一段时间了,为了查缺补漏,把知识点系统化,准备写几篇博文梳理下webservice的知识点,这是第一篇,对webservice进行大致的介绍. 1.什么是webservic ...

  3. 谈一款MOBA游戏《码神联盟》的服务端架构设计与实现

    一.前言 <码神联盟>是一款为技术人做的开源情怀游戏,每一种编程语言都是一位英雄.客户端和服务端均使用C#开发,客户端使用Unity3D引擎,数据库使用MySQL.这个MOBA类游戏是笔者 ...

  4. java中常用的包、类、以及包中常用的类、方法、属性----sql和text\swing

    java中常用的包.类.以及包中常用的类.方法.属性 常用的包 java.io.*; java.util.*; java.lang.*; java.sql.*; java.text.*; java.a ...

  5. 如何更换git托管

    有时候会遇到需要更换代码托管平台,从github,gitlab或者Bitbucket迁移到其它平台,过程中可能遇到不少问题,本文从是否保留历史提交记录两种需求出发,介绍一下基于git托管平台的迁移方法 ...

  6. 导入 theano 失败。“cannot import name gof”

    按照网上教程安装好了 theano 之后,import theano 出现错误."cannot import name gof".网上找了很多教程,都不可行.最后找到如下教程.亲测 ...

  7. 设计模式--单例模式(Singleton pattern)及应用

    单例模式 参考文档: 该文仅介绍spring的单例模式:spring 的单例模式 介绍原理:Spring的单例模式底层实现 参考书籍:漫谈设计模式:从面向对象开始-刘济华.pdf 1. 单例模式解析 ...

  8. windows系统查看支持最大内存

    1.使用快捷键:win+r打开命令窗口. 按回车到命令界面 2.弹出如下命令界面,在界面C:\Users\Administrator>处输入wmic memphysical get maxcap ...

  9. Kotlin + Spring Boot 请求参数验证

    编写 Web 应用程序的时候,经常要做的事就是要对前端传回的数据进行简单的验证,比如是否非空.字符长度是否满足要求,邮箱格式是否正确等等.在 Spring Boot 中,可以使用 Bean Valid ...

  10. iOS耗电量测试

    iOS耗电量测试 本文主要介绍的是使用Energy Diagnostics Instruments来进行iOS耗电量测试. 一.使用方法: 1)iOS 设置选项 ->开发者选项 ->log ...