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

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

概述ASP.NET全栈开发之在MVC中使用服务端验证(二) 首先声明,这篇博文是完善.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();        }

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

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

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

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

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

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

同样没触发。

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

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

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

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

以上是内存溢出为你收集整理的ASP.NET全栈开发之在MVC中使用服务端验证(二)全部内容,希望文章能够帮你解决ASP.NET全栈开发之在MVC中使用服务端验证(二)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1211232.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-04
下一篇 2022-06-04

发表评论

登录后才能评论

评论列表(0条)

保存