Maison  >  Article  >  développement back-end  >  Développement full stack ASP.NET utilisant la validation côté serveur dans MVC (2)

Développement full stack ASP.NET utilisant la validation côté serveur dans MVC (2)

无忌哥哥
无忌哥哥original
2018-07-20 09:20:121754parcourir

Tout d'abord, permettez-moi de préciser que cet article de blog concerne l'utilisation de la vérification côté serveur dans MVC pour améliorer le développement full-stack .ASP.NET. Par conséquent, je ne développerai pas le contenu répété. pratique, puis pour l'améliorer, cet article de blog est le même, basé sur ce que j'ai lu "Développement full stack .ASP.NET utilisant la vérification côté serveur dans MVC".

Dans l'article précédent, bien que nous ayons terminé la vérification côté serveur, nous devons toujours appeler le validateur dans l'action pour vérification, comme ceci.

   [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();
        }

C'est dégoûtant si j'ai besoin de vérifier, je dois écrire comme ça dans chaque action. Si je veux vraiment. Si vous faites cela dans chaque action, je pense que vous détesterez certainement ce code. Du moins je le pense. Donc j’ai détesté la façon dont je l’ai écrit avant.

Qu'est-ce que je veux faire maintenant ? Nous savons que MVC dispose en fait d'une validation de données intégrée. Je ne vais pas trop le présenter ici (regarder correctement le volant de temps en temps présente de nombreux avantages). Voici une brève description de son utilisation.

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

Par rapport à la façon dont nous l'avons écrit auparavant, c'est beaucoup plus simple, mais je pense toujours qu'il doit toujours appeler ModelState dans chaque action. IsValid, bien qu'il n'y en ait qu'un si, mais ce n'est pas ce que je veux, j'espère que ça pourra être comme ça

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

pour ne pas affecter ma normale programmation, mais je ne fais pas non plus de choses répétitives.

En d’autres termes, les données sont effectivement vérifiées avant d’exécuter mon Action.

Nous avons donc pensé au Filter et OnActionExecuting fournis par MVC. Ouvrez notre ControllerEx et réécrivez OnActionExecuting dedans. Il a un paramètre ActionExecutingContext. Nous le comprenons grossièrement à travers le nom. , alors il doit avoir installé les données liées à l'action

Je n'écrirai pas l'encre, mais allez d'abord directement au code. En fait, ces codes sont exactement ce que je viens d'écrire, je ne sais pas. beaucoup sur ce paramètre. Essayez-les un par un, et vous comprendrez lentement.

 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);
        }

Dans OnActionExecuting, nous définissons d'abord une existError pour déterminer si la vérification a échoué, puis nous parcourons filterContext.ActionParameters.Values

Dans filterContext, nous voyons que ActionParameters concerne les paramètres d'Action, grâce au débogage, j'ai trouvé qu'il s'agit d'une collection dont la clé est le nom du paramètre. Par exemple, prenez notre Person.

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

Il y a une donnée dans la collection filterContext.ActionParameters, la clé est "model" et la valeur est model

Nous pouvons donc obtenir tous les paramètres de chaque action en parcourant filterContext.ActionParameters.Value, et chaque paramètre peut obtenir son nom de type via .getType().Name Par exemple, le type de modèle ici est. Personne Donc filterContext.ActionParameters["model"].GetType().Name est "Person".

Maintenant que nous savons de quel type d'entité il s'agit, comment pouvons-nous obtenir le validateur spécifique ? Pensez à notre configuration de validateur Person = PersonValidator. Ce n'est pas une relation un-à-un, mais il est impossible de revenir à l'usine via un commutateur. Dans ce cas, une méthode d'usine doit être maintenue. Bien sûr que non, cela nécessite l'utilisation de la puissante technologie de réflexion fournie par .NET

Parfois, nous avons un objet anonyme, qui est un objet, mais nous ne savons pas de quel type il s'agit et comment l'obtenir . Qu'en est-il des attributs ?

J'ai une méthode qui peut résoudre ce problème.

 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);
        }
    }

En termes d'utilisation, transmettez un nom d'attribut et un objet, et renvoyez un attribut d'objet.

Regardons ce qui a été fait en interne.

Obtenez d'abord le type, puis obtenez l'attribut exécuté. Oh, cet attribut n'est pas un véritable attribut. Il s'agit du type PropertyInfo, qui est le type de données en réflexion. mais si nous voulons, que dois-je faire pour obtenir la valeur réelle de l'attribut ? En fait, il vous suffit d'appeler son GetValue. Il a un paramètre. Ce paramètre fait référence à l'obtention des attributs de cet objet, il suffit donc de transmettre l'objet.

Avec cette fondation, en repensant à notre objectif, connaissant Person, il existe un objet appelé ValidatotHub avec une propriété PersonValidator, nous n'avons donc besoin que d'obtenir la propriété PersonValidator dans un objet appelé ValidatorHub. (Person est remplaçable et dépend du type de paramètre. Cela a déjà été expliqué. Voici Person à titre d'exemple)

Maintenant, il y a un problème. Le PersonValidator que nous obtenons est de type objet. Ce n'est pas le cas. facile à utiliser pour moi, et nous ne pouvons pas le convertir explicitement en un type spécifique, car qui sait quel est le type spécifique. Si c'est écrit à mort, ce sera cool. Alors vous ne pouvez certainement pas utiliser un commutateur pour le maintenir. Cela n'augmenterait-il pas encore la charge de travail ?

我们慢慢发现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。

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn