Home > Article > Backend Development > ASP.NET full stack development using server-side validation in MVC (2)
First of all, let me state that this blog post is about using server-side verification in MVC to improve .ASP.NET full-stack development. Therefore, I will not elaborate on the repeated content. Many problems are discovered in practice, and then To improve it, this blog post is the same, based on what I have read ".ASP.NET full stack development using server-side verification in MVC".
In the previous article, although we completed the server-side verification, we still need to call the validator in the Action for verification, like this.
[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(); }
It’s disgusting. If I need to verify, I need to write like this in every Action. It’s just an experiment. If I really want to verify it in every If you do this in Action, I think you will definitely hate this code. At least I think so. So I hated the way I wrote it before.
What do I want to do now? We know that MVC actually has a built-in data validation. I won't introduce it too much here (occasionally looking at the wheel properly has many benefits). Here is a brief description of its usage.
[HttpPost] public ActionResult ValidatorTest(Person model) { if (ModelState.IsValid) { /// ok } return View(); }
It is much more streamlined than what we wrote before, but I still think that he still needs to call ModelState.IsValid in each Action. Although there is only one if, this is not what I want, I hope it can be like this
[HttpPost] public ActionResult ValidatorTest(Person model) { // // 一大堆代码 // return Redirect("https://www.baidu.com"); }
Do not affect my normal programming, and I will not go Do something repetitive.
In other words, the data is actually verified before executing my Action.
So we thought of the Filter and OnActionExecuting provided by MVC. Open our ControllerEx and rewrite OnActionExecuting in it. It has a parameter ActionExecutingContext. We roughly understand it through the name. This parameter is an Action-related context. , then he must have installed Action-related data.
I won’t write the ink, but go directly to the code. In fact, these codes are just what I just wrote. I don’t know much about this parameter. Try them one by one, and you'll get the hang of it slowly.
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); }
In OnActionExecuting, we first defined an existError to determine whether the verification failed, and then we traversed filterContext.ActionParameters.Values
In filterContext, we see that ActionParameters is about the parameters of Action. Through debugging, I found that it is a collection whose key is the parameter name. For example, take our Person.
[HttpPost] public ActionResult ValidatorTest(Person model) { // // 一大堆代码 // return Redirect("https://www.baidu.com"); }
There is a data in the filterContext.ActionParameters collection, the key is "model" and the value is model
So we can get all the parameters of each Action by traversing filterContext.ActionParameters.Value, and each parameter can get its type name through .getType().Name. For example, the model type here is Person, so filterContext.ActionParameters["model"].GetType().Name is "Person".
Now that we know what type of entity it is, how do we get the specific validator? Think about our validator configuration Person = PersonValidator. That is too simple. This is not a one-to-one relationship, but it is impossible to return to the factory through a switch. In this case, a factory method needs to be maintained. Of course not, this requires the use of the powerful reflection technology provided by .NET
Sometimes we have an anonymous object, which is an object, but we don’t know what type it is and how to get it. What about attributes?
I have a method that can solve this problem.
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); } }
In terms of usage, pass an attribute name and object in, and return an object attribute.
Let’s take a look at what’s been done internally.
First get the type, and then get the executed attribute. Oh, this attribute is not a real attribute. This is the PropertyInfo type, which is the data type in reflection. It is not a real attribute value, but if we want What should I do to get the real attribute value? In fact, you only need to call its GetValue. It has a parameter. This parameter refers to getting the attributes on that object, so just pass the object in.
With this foundation in mind, looking back at our purpose, we know that Person, there is an object called ValidatotHub with a property PersonValidator in it, so we only need to get the PersonValidator property in an object called ValidatorHub. (Person is replaceable and is based on the parameter type. It has been explained before. Here is Person as an example)
Now there is a problem. The PersonValidator we get is of object type. The object type It's not easy for me to use, and we can't explicitly convert it to a specific type, because who knows what the specific type is. If it is written to death, it will be cool. Then you definitely can't use a switch to maintain it. Wouldn't that increase the workload again?
我们慢慢发现PersonValidator继承自AbstractValidator8abf60ac54173a2785e603c7a1f95b4e 很显然它的基类也需要一个具体类型,不行,继续往上走,诶,发现了AbstractValidator8742468051c85b06f0a0af9e3e506b5c继承自IValidator,并且IValidator定义了Validate方法。这不就好了吗,我as 为IValidator类型,就可以用了。这里使用了(里氏转换原则)。我尽量写得通俗易懂,也将许多基础东西提一下,但不肯能面面俱到,所以还是建立在一部分基础之上的。(当然更重要的一点是,通过这次遇到的问题让我以后在设计泛型类结构的时候,都要去继承一个非泛型的接口,如果FluentValidator没有继承自IValidator 而只是继承自IValidator8742468051c85b06f0a0af9e3e506b5c其实从简单使用上来讲,并没有什么影响啊,但到了我们刚刚这里,问题就出来了,所以这也是给我们狠狠地上了一课啊)
现在我就可以在这里进行验证了,我们知道value 就是那个model 所以直接对他进行验证,验证会返回一个ValidationResult类型接下来的事我就不解释了,相信上一章已经讲得很清楚了。最后根据是否存在错误在进行提前处理,如果有错误的话就直接返回视图呈现错误了,连咱们的Action都不执行了。好了,到这里咱们昨天讲得OnActionExecuted 可以直接Delete拉 。
我们现在把ValidatorTest里的验证代码都去掉来测试一下。
[HttpPost] public ActionResult ValidatorTest(Person model) { // // 一大堆代码 // return Redirect("https://www.baidu.com"); }
在 ValidatorTest 里打上断点,然后什么都不填,直接提交。
断点没触发,但错误消息已呈现。多试几次~.
同样没触发。
那我们来一次正确的验证。
断点触发了。并且值都通过了校验
F5放行,最终我们的页面跳转到了 www.baidu.com。
好了,小伙伴们还不快去改改代码造就幸福生活。
The above is the detailed content of ASP.NET full stack development using server-side validation in MVC (2). For more information, please follow other related articles on the PHP Chinese website!