由表单验证说起,关于在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 ...
随机推荐
- [LeetCode] Shortest Word Distance II 最短单词距离之二
This is a follow up of Shortest Word Distance. The only difference is now you are given the list of ...
- Gulp 入门
1. 安装 Node 环境 参考 http://www.cnblogs.com/zichi/p/4627728.html,注意一起安装 npm 工具,并把路径保存到环境变量中(安装过程中会有提醒) 安 ...
- Snowflake 全局唯一Id 生成
/// <summary> /// From: https://github.com/twitter/snowflake /// An object that generates IDs. ...
- Backbone.js应用基础
前言: Backbone.js是一款JavaScript MVC应用框架,强制依赖于一个实用型js库underscore.js,非强制依赖于jquery:其主要组件有模型,视图,集合,路由:与后台的交 ...
- C 语言学习 第六次作业总结
本次作业,同学们开始学习函数.通过之前和同学们的沟通,似乎同学们在这里遇到的问题比较多.下面,我先帮同学们整理下函数的相关知识点. 什么是函数 首先,需要明确的是,什么是函数.所谓函数,也就是一段有名 ...
- 两种适用于中小量数据的mysql数据备份
近来项目的业务量开始大了,感觉如果数据不周期性地备份一下,很可能会出现问题,虽然我每天都有阿里云的自动快照,上网找了一下方法,找到两种相对简单而又适合中小项目或者中小公司的数据备份策略,以下都是数据库 ...
- shell-for循环
sheel语言for循环格式 for var in item1 item2 ... itemN do command1 command2 ... commandN done 案例1 #!/bin/ba ...
- Spring Boot
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.通过 ...
- 【IT】公司FTP服务器使用说明
FTP服务器的作用:----------------------------------------------1.员工个人或者部门资料临时备份(而不是永久归档): 2.部门或员工间交换巨大资料: 3 ...
- JavaScript事件详解-jQuery的事件实现(三)
正文 本文所涉及到的jQuery版本是3.1.1,可以在压缩包中找到event模块.该篇算是阅读笔记,jQuery代码太长.... Dean Edward的addEvent.js 相对于zepto的e ...