在web开发中必不可少的会遇到表单验证的问题,为避免数据在写入到数据库时出现异常,一般比较安全的做法是前端会先做一次验证,通过后把数据提交到后端再验证一次,因为仅仅靠前端验证是不安全的,有太多的http请求工具可以轻松绕过你的前端验证把危险数据提交到后端,所以,之前不做后端参数验证的同学赶快检查一下你的代码~别中招了

那么,故事就是有关于后端验证。

这里举一个项目中真实的注册场景,账号注册主要包含2个信息:手机号和验证码,因为我这里是用webapi的post方式从前端拿数据,所以封装成了一个MemberRegister对象。以最基础的非空验证为例,通常要写如下代码:

如果还要加上手机号格式验证,还得再来一个if。一旦要验证的信息多的话代码行就会很多,看着很冗余。想着既然做的都是同一件事,那能不能封装一下减少代码行?架构师allen说可以试一下链式编程,也就是类似Jquery的xxxx.attr().css().html().show()这样,看起来还不错的样子,那就干吧。

其实C#里也有类似的用法,比如Linq里面的xxxx.Where().OrderBy().Select()这种,但是这种实际上每次返回的都是不同的对象,然后执行对象里的方法,这并不适合我的需求,因为我执行的验证方法肯定都是同一个,比如validate().validate().validate()这种,于是决定用扩展方法来实现。先定义一个被扩展的对象:

public class ValidateResult<T>
{
public List<string> Errors { get; set; }
public T Entity { get; private set; } public ValidateResult(T entity)
{
Errors = new List<string>();
Entity = entity;
}
}

定义扩展方法:

public static ValidateResult<T> Validate<T>(this ValidateResult<T> target, Predicate<T> predicate, string errorMessage)
{
if (!predicate(target.Entity))
{
target.Errors.Add(errorMessage) ;
}
return target;
}

使用办法:

var error = new ValidateResult<MemberRegister>(model)
.Validate(m => m != null, ResponseTip.ParamError)
.Validate(m => !string.IsNullOrEmpty(m.Phone), ResponseTip.PhoneRequired)
.Validate(m => !string.IsNullOrEmpty(m.CodeValue), ResponseTip.ValidateCodeRequired)
.Errors;

理想中的情况是,可以判断error里面有没有错误信息,如果有的话就返回错误信息,没有就做后面的操作。但实际上碰到一个问题,当model为null的时候,第一步验证没有问题,但第二步的时候就报错了,未将对象引用到实例,原因是model已经是null了再取model.Phone不出错才怪。问题找到了,那就想着如果model为null就不执行后面的验证了,想法不错但想了很久就是没找到办法实现。不知所措的时候,断点跟了一下出错的代码,发现报错的地方是在执行if (!predicate(target.Entity))的时候,于是换了一个思路,改进一下代码:

    public class ValidateResult<T>
{
public string Error { get; set; }
public T Entity { get; private set; } public ValidateResult(T entity)
{
Entity = entity;
}
}

扩展方法:

        public static ValidateResult<T> Validate<T>(this ValidateResult<T> target, Predicate<T> predicate, string errorMessage)
{
if (string.IsNullOrEmpty(target.Error))
{
if (!predicate(target.Entity))
{
target.Error = errorMessage;
}
}
return target;
}

改进后的代码把ValidateResult里的Errors取消了换成了string类型的Error(要那么多错误提示也没什么用,一个就够了),然后验证失败后就更新这个属性,验证的时候如果这个属性string.IsNullOrEmpty(target.Error)就表示前面的验证都通过了本次可以继续验证,如果! string.IsNullOrEmpty(target.Error)就表示前面的验证已经失败了本次不用验证,要验证的对象原封不动的返回。这样子就不会报错了,然后调用结果判断Error是否NullOrEmpty再做相应操作。测试一下,没有问题。代码演变为:

优点

可读性个人觉得并不比直接if差,分行显示的话还是能很清晰看出具体的验证项。

省去了每次判断的if语句和return,支持自定义验证规则和错误提示。

减少了代码的行数。

缺点

某次验证失败不能中断后面的验证,多执行了不必要的代码,这点用if可以避免。

总结

完了以后去网上找了一些C#链式编程的问题,有支持的也有反对的,反对的人说代码可读性不太好、简单的问题复杂化等等。经过实际实践,我觉得这个问题偏向于个人喜好,谈不上好坏,怎样用着爽、开发效率高就行。不喜欢的还请轻点拍砖。

当然,关于这个问题有更好解决方案的希望能交流一下。

由表单验证说起,关于在C#中尝试链式编程的实践的更多相关文章

  1. ASP.NET MVC Jquery Validate 表单验证的多种方式

    在我们日常开发过程中,前端的表单验证很重要,如果这块处理不当,会出现很多bug .但是如果处理的好,不仅bug会很少,用户体验也会得到很大的提升.在开发过程中我们可以不借助 JS 库,自己去手写 JS ...

  2. 在AngularJS中实现自定义表单验证

    除了一些已经定义好了的验证(例如 必填项.最小长度.最大长度)之外,更常用的,还是需要我们自己定义表单验证,这样才能对于项目中遇到的很多非常规问题给出自己的合适的解决方案. 在表单中控制变量 表单的属 ...

  3. Webx之表单验证

    引入服务器端表单验证service,是通过在webx.xml中通过服务引入的方式完成的.例如,在user相关信息的表单验证的产生过程是这样的:webx-user.xml通过 <beans:imp ...

  4. [php基础]PHP Form表单验证:PHP form validator使用说明

    在PHP网站开发建设中,用户注册.留言是必不可少的功能,用户提交的信息数据都是通过Form表单提交,为了保证数据的完整性.安全性,PHP Form表单验证是过滤数据的首要环节,PHP对表单提交数据的验 ...

  5. Jquery Validate 表单验证的多种方式

    ASP.NET MVC Jquery Validate 表单验证的多种方式 在我们日常开发过程中,前端的表单验证很重要,如果这块处理不当,会出现很多bug .但是如果处理的好,不仅bug会很少,用户体 ...

  6. vue 常用的表单验证,包括手机号码,固定电话和身份证...

    <template> <div> <pl-content-box> <pl-page-nav :show-previous=true></pl-p ...

  7. jQuery学习之路(8)- 表单验证插件-Validation

    ▓▓▓▓▓▓ 大致介绍 jQuery Validate 插件为表单提供了强大的验证功能,让客户端表单验证变得更简单,同时提供了大量的定制选项,满足应用程序各种需求.该插件捆绑了一套有用的验证方法,包括 ...

  8. 玩转spring boot——AOP与表单验证

    AOP在大多数的情况下的应用场景是:日志和验证.至于AOP的理论知识我就不做赘述.而AOP的通知类型有好几种,今天的例子我只选一个有代表意义的“环绕通知”来演示. 一.AOP入门 修改“pom.xml ...

  9. form表单验证-Javascript

    Form表单验证: js基础考试内容,form表单验证,正则表达式,blur事件,自动获取数组,以及css布局样式,动态清除等.完整代码如下: <!DOCTYPE html PUBLIC &qu ...

随机推荐

  1. ngx_http_upstream_module模块.md

    ngx_http_upstream_module ngx_http_upstream_module模块用于定义可由proxy_pass,fastcgi_pass,uwsgi_pass,scgi_pas ...

  2. IIS7.0部署MVC/WebApi项目,报404.4错误

    在web.config中添加如下的配置试试: <system.webServer> <modules runAllManagedModulesForAllRequests=" ...

  3. PAT 1046. 划拳(15)

    划拳是古老中国酒文化的一个有趣的组成部分.酒桌上两人划拳的方法为:每人口中喊出一个数字,同时用手比划出一个数字.如果谁比划出的数字正好等于两人喊出的数字之和,谁就赢了,输家罚一杯酒.两人同赢或两人同输 ...

  4. 《虚拟伙伴》AR增强现实应用开发总结

    一.概述 1.1选题背景 随着时代的发展,人们的生活节奏越来越快,生活质量也越来越高,但却在繁忙之中忽略或者忘记了关心自己成长时代最重要或者最正确的事情和道理.虽然现在有很多社交平台,如微博,微信,f ...

  5. Url重写——伪静态实现

    简述: 在我们浏览网站的时候,很多都是以.html结尾的.难道这些都是静态网页么?其实不是的,它们很多是伪静态 那么什么是伪静态?顾名思义,就是假的静态页面.通过某种设置让你看成是静态的. Q:为何要 ...

  6. ACM提交结果简介

    如果你看到红色的"Accepted",那么,恭喜你,你已经成功的解决了该问题! 如果你收到的是如下的信息,则还需要继续检查你的程序: Wrong Answer (WA) : 输出结 ...

  7. 启动Maven项目启动报错:java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener

    tomcat在发布项目的时候没有同时发布maven依赖所添加的jar包,你需要设置一下eclipse:项目 -> 属性 -> Deployment Assembly -> Add - ...

  8. python venv下安装mysql出错 解决方法

    1.首先使用exe文件安装python-mysql.链接: http://pan.baidu.com/s/1kVqILTX 密码: manj. 2.虚拟环境创建后,我们把已经在公共环境使用exe安装好 ...

  9. OAuth2.0相关知识

    自己总结的可能有误差. 大致分为6个步骤: 1.注册相关应用,获取client_id,client_secret.2.第三方请求用户授权.用户点击按钮同意授权后,授权服务器将生成一个用户凭证(code ...

  10. iife js

    摘自:http://dz.sdut.edu.cn/blog/subaochen/2016/02/%E8%AF%B4%E4%B8%80%E8%AF%B4js%E7%9A%84iife/ 1 定义 IIF ...