由表单验证说起,关于在C#中尝试链式编程的实践
在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#中尝试链式编程的实践的更多相关文章
- ASP.NET MVC Jquery Validate 表单验证的多种方式
在我们日常开发过程中,前端的表单验证很重要,如果这块处理不当,会出现很多bug .但是如果处理的好,不仅bug会很少,用户体验也会得到很大的提升.在开发过程中我们可以不借助 JS 库,自己去手写 JS ...
- 在AngularJS中实现自定义表单验证
除了一些已经定义好了的验证(例如 必填项.最小长度.最大长度)之外,更常用的,还是需要我们自己定义表单验证,这样才能对于项目中遇到的很多非常规问题给出自己的合适的解决方案. 在表单中控制变量 表单的属 ...
- Webx之表单验证
引入服务器端表单验证service,是通过在webx.xml中通过服务引入的方式完成的.例如,在user相关信息的表单验证的产生过程是这样的:webx-user.xml通过 <beans:imp ...
- [php基础]PHP Form表单验证:PHP form validator使用说明
在PHP网站开发建设中,用户注册.留言是必不可少的功能,用户提交的信息数据都是通过Form表单提交,为了保证数据的完整性.安全性,PHP Form表单验证是过滤数据的首要环节,PHP对表单提交数据的验 ...
- Jquery Validate 表单验证的多种方式
ASP.NET MVC Jquery Validate 表单验证的多种方式 在我们日常开发过程中,前端的表单验证很重要,如果这块处理不当,会出现很多bug .但是如果处理的好,不仅bug会很少,用户体 ...
- vue 常用的表单验证,包括手机号码,固定电话和身份证...
<template> <div> <pl-content-box> <pl-page-nav :show-previous=true></pl-p ...
- jQuery学习之路(8)- 表单验证插件-Validation
▓▓▓▓▓▓ 大致介绍 jQuery Validate 插件为表单提供了强大的验证功能,让客户端表单验证变得更简单,同时提供了大量的定制选项,满足应用程序各种需求.该插件捆绑了一套有用的验证方法,包括 ...
- 玩转spring boot——AOP与表单验证
AOP在大多数的情况下的应用场景是:日志和验证.至于AOP的理论知识我就不做赘述.而AOP的通知类型有好几种,今天的例子我只选一个有代表意义的“环绕通知”来演示. 一.AOP入门 修改“pom.xml ...
- form表单验证-Javascript
Form表单验证: js基础考试内容,form表单验证,正则表达式,blur事件,自动获取数组,以及css布局样式,动态清除等.完整代码如下: <!DOCTYPE html PUBLIC &qu ...
随机推荐
- iframe的优缺点
HTML框架简述 一个浏览器窗体可以通过几个页面的组合来显示.我们可以使用框架来完成(frames)这项工作.(框架可以把HTML文档分为多个页面) 框架页使用了表格的方式组合,可以分为数行与 ...
- CMakeList.txt/Clion中添加头文件和库
cmake_minimum_required(VERSION 3.6) project(capi_lua) include_directories(/usr/include) find_library ...
- Why many EEG researchers choose only midline electrodes for data analysis EEG分析为何多用中轴线电极
Source: Research gate Stafford Michahial EEG is a very low frequency.. and literature will give us t ...
- C#调用天气查询服务
先引入天气查询服务 1.有点引用导入服务引用 //实例化 web引用名.WeatherWebService cn = new web引用名.WeatherWebService() ...
- [LeetCode] Longest Common Prefix 最长共同前缀
Write a function to find the longest common prefix string amongst an array of strings. 这道题让我们求一系列字符串 ...
- maven-过滤不打入包的文件
在使用maven打包时,有时有些测试文件,或者配置都希望打入到架包中 此时就需要使用将不用的文件过滤,maven有很方便的过滤插件.因工作时间,暂不讨论.本次讨论一个非常简单除暴的方法,通过配置ecl ...
- SOD让你的旧代码焕发青春
最近接手了一个旧的系统,各种陈旧的问题比较多,其中最棘手的就是操作数据库的部分,具体如下: 1.核心库是一个最后修改时间为2008年的库,先不说有多陈旧,现在这个库只是一个DLL文件,没有源码,也已经 ...
- 在Arcscene绘制管线三维横断面(AE绘制三维点阵文字)
根据数据信息动态生成三维管线及横断面表格.效果图如下: 在获取信息后,直接构造点阵进行文字绘制即可. 绘制IElement代码: /// <summary> /// 绘制三维文字 /// ...
- Java中创建对象的5种方式
作为Java开发者,我们每天创建很多对象,但我们通常使用依赖管理系统,比如Spring去创建对象.然而这里有很多创建对象的方法,我们会在这篇文章中学到. Java中有5种创建对象的方式,下面给出它们的 ...
- pycharm5注册码
43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0I0QTczWVlKIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...