0

0

ASP.NET全栈开发之在MVC中使用服务端验证(二)

无忌哥哥

无忌哥哥

发布时间:2018-07-20 09:20:12

|

2006人浏览过

|

来源于php中文网

原创

 首先声明,这篇博文是完善.asp.net全栈开发之在mvc中使用服务端验证 的,所以重复内容,我就不过多的阐述,很多问题都是在实践中去发现,然后再去完善,这篇博文也一样,建立在已阅 “.asp.net全栈开发之在mvc中使用服务端验证” 的基础上。

在上一篇中,虽然我们完成了服务端验证,但我们还是需要在Action里调用验证器来进行验证,像这样。

   [HttpPost]        
       public ActionResult ValidatorTest(Person model)
        {var result = this.ValidatorHub.PersonValidator.Validate(model);            
            if (result.IsValid)
            { 
                return Redirect("https://www.baidu.com");
            }else
            { 
                this.ValidatorErrorHandler(result);
            }            
            return View();
        }

Dang.ai
Dang.ai

Dang.ai是一个AI工具目录集,已收集超过5000+ AI工具

下载

很可恶,如果我需要验证,我需要在每一个Action 里像这样写,一次实验也就罢了,如果真要在每个Action里像这样干,我想到时候你一定会很讨厌这些代码的。至少我是这样认为。所以我很讨厌我之前的写法。

现在我想干嘛呢?我们知道其实MVC内置了一个数据校验。这里不过多介绍它,(偶尔适当的照照轮子,也有许多好处的)。这里简单描述下它的用法。

  [HttpPost]        
  public ActionResult ValidatorTest(Person model)
        {
            if (ModelState.IsValid)
            { /// ok }            
            return View();
        }

和咱们之前那样写比起来是精简了许多,但我还是觉得吧,他还是要在每个Action 里调用ModelState.IsValid,虽然只有一个if,但这不是我想要的,我希望它能像这样

  [HttpPost]        
      public ActionResult ValidatorTest(Person model)
        {            
        // 
            //  一大堆代码            
            //            
                return Redirect("https://www.baidu.com");
        }

不要影响我正常的编程,而我也不去做哪些重复的事。

换句话说,其实就是在执行我Action之前就去把数据给校验了。

于是我们想到了MVC给我们提供的Filter,OnActionExecuting,打开我们的ControllerEx,在里面重写OnActionExecuting,他有一个参数ActionExecutingContext,通过名字我们大致了解了,这个参数是个Action相关的上下文,那他一定装了Action相关的数据

我就不墨迹了,先直接上代码,其实这些代码也只是我刚刚才写出来的而已,我对这个参数也不是很了解,通过一个一个去尝试,慢慢得就试出来了。

 protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {            
            var existError = false;            
            foreach (var value in filterContext.ActionParameters.Values)
            {                
                var modelValidatorPropertyInfo = this.ValidatorHub.GetType().GetProperty(value.GetType().Name + "Validator");                if (modelValidatorPropertyInfo != null)
                {                    
                    var modelValidator = modelValidatorPropertyInfo.GetValue(this.ValidatorHub) as IValidator;                    var validateResult = modelValidator.Validate(value);                    if (!validateResult.IsValid)
                    {                        
                          this.ValidatorErrorHandler(validateResult);
                        existError = true;
                    }

                }
            }            
            if (existError)
            {
                ViewData["Error"] = DicError;
                filterContext.Result = View();
            }            
            base.OnActionExecuting(filterContext);
        }

在 OnActionExecuting 里,我们首先定义了一个existError,用来判断是否验证失败的,然后我们遍历了 filterContext.ActionParameters.Values

在filterContext 里,我们看到ActionParameters 是关于Action的参数的,通过调试我发现,他是一个集合,其键是参数名,比如拿我们这个Person来讲。

 [HttpPost]        
     public ActionResult ValidatorTest(Person model)
        {            
        // 
            //  一大堆代码            
            //            
                return Redirect("https://www.baidu.com");
        }

filterContext.ActionParameters 集合里就有一个数据,其键是"model" 值呢 model

所以呢我们通过遍历filterContext.ActionParameters.Value 就能取出每一个Action的所有参数了,而每一个参数通过.getType().Name 则能取出他的类型名,比如这里model类型是Person 所以filterContext.ActionParameters["model"].GetType().Name 就是“Person”了。

知道了实体是什么类型,如何获取具体验证器呢?想想我们的验证器配置 Person = PersonValidator 那太简单了,这不是一对一的关系嘛,但总不可能通过一个switch 去工厂返回吧,那这样还需要维护一个工厂方法。当然不是咯,这就要用到咱.NET 提供的强大反射技术

有时候我们有一个匿名对象,是一个object的时候,又不知道它具体是什么类型,如何取它的属性呢?

我这有一个方法,他能解决这个问题。

 public static class ReflectHelper
    {        
        public static object GetPropertyByAnonymousObject(string propertyName, object obj)
        {            
            var property = obj.GetType().GetProperties().Where(p => p.Name == propertyName).FirstOrDefault();            if (property == null)
            {                
                throw new Exception(string.Format("{0}对象未定义{1}属性", nameof(obj), nameof(propertyName)));
            }            
            return property.GetValue(obj);
        }
    }

从使用上,传递一个属性名和对象进来,返回一个object的属性。

我们看看内部都做了些什么。

首先获取类型,然后获取执行的属性,诶,这个属性可不是真的属性哦,这个是PropertyInfo类型,是反射里的数据类型,它不是真正的属性值,但我们如果想要获取真正的属性值怎么办呢?其实只需要调用他的GetValue就行了,他有一个参数,这个参数是指获取那个对象上的属性,于是把object传进去就行。

有了这个基础,反观我们的目的,知道了Person,有一个对象叫ValidatotHub 里面有个属性PersonValidator ,所以我们只需要获取一个叫ValidatorHub对象里的PersonValidator属性就行了。(Person是可替换的,是根据参数类型来的,前面已经解释过了,这里以Person举例)

现在有个问题了,我们取到的PersonValidator 是一个object类型的,object类型我可不好使用啊,我们又不能显示的转换为具体类型,因为谁知道具体类型是啥呢。如果写死了就凉了。那肯定也不能用个switch来维护啊,那样不又增加工作量了吗。

我们慢慢发现PersonValidator继承自AbstractValidator 很显然它的基类也需要一个具体类型,不行,继续往上走,诶,发现了AbstractValidator继承自IValidator,并且IValidator定义了Validate方法。这不就好了吗,我as 为IValidator类型,就可以用了。这里使用了(里氏转换原则)。我尽量写得通俗易懂,也将许多基础东西提一下,但不肯能面面俱到,所以还是建立在一部分基础之上的。(当然更重要的一点是,通过这次遇到的问题让我以后在设计泛型类结构的时候,都要去继承一个非泛型的接口,如果FluentValidator没有继承自IValidator 而只是继承自IValidator其实从简单使用上来讲,并没有什么影响啊,但到了我们刚刚这里,问题就出来了,所以这也是给我们狠狠地上了一课啊)

现在我就可以在这里进行验证了,我们知道value 就是那个model 所以直接对他进行验证,验证会返回一个ValidationResult类型接下来的事我就不解释了,相信上一章已经讲得很清楚了。最后根据是否存在错误在进行提前处理,如果有错误的话就直接返回视图呈现错误了,连咱们的Action都不执行了。好了,到这里咱们昨天讲得OnActionExecuted 可以直接Delete拉 。

我们现在把ValidatorTest里的验证代码都去掉来测试一下。

        [HttpPost]        
        public ActionResult ValidatorTest(Person model)
        {            
            // 
                //  一大堆代码            
                //            
                return Redirect("https://www.baidu.com");
        }

在 ValidatorTest 里打上断点,然后什么都不填,直接提交。

断点没触发,但错误消息已呈现。多试几次~.

同样没触发。

那我们来一次正确的验证。

 

断点触发了。并且值都通过了校验

F5放行,最终我们的页面跳转到了 www.baidu.com。

好了,小伙伴们还不快去改改代码造就幸福生活。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

178

2026.01.28

包子漫画在线官方入口大全
包子漫画在线官方入口大全

本合集汇总了包子漫画2026最新官方在线观看入口,涵盖备用域名、正版无广告链接及多端适配地址,助你畅享12700+高清漫画资源。阅读专题下面的文章了解更多详细内容。

35

2026.01.28

ao3中文版官网地址大全
ao3中文版官网地址大全

AO3最新中文版官网入口合集,汇总2026年主站及国内优化镜像链接,支持简体中文界面、无广告阅读与多设备同步。阅读专题下面的文章了解更多详细内容。

79

2026.01.28

php怎么写接口教程
php怎么写接口教程

本合集涵盖PHP接口开发基础、RESTful API设计、数据交互与安全处理等实用教程,助你快速掌握PHP接口编写技巧。阅读专题下面的文章了解更多详细内容。

2

2026.01.28

php中文乱码如何解决
php中文乱码如何解决

本文整理了php中文乱码如何解决及解决方法,阅读节专题下面的文章了解更多详细内容。

4

2026.01.28

Java 消息队列与异步架构实战
Java 消息队列与异步架构实战

本专题系统讲解 Java 在消息队列与异步系统架构中的核心应用,涵盖消息队列基本原理、Kafka 与 RabbitMQ 的使用场景对比、生产者与消费者模型、消息可靠性与顺序性保障、重复消费与幂等处理,以及在高并发系统中的异步解耦设计。通过实战案例,帮助学习者掌握 使用 Java 构建高吞吐、高可靠异步消息系统的完整思路。

8

2026.01.28

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

24

2026.01.27

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

122

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

72

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号