溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

ASP.NET全棧開發(fā)之在MVC中使用服務(wù)端驗(yàn)證的示例

發(fā)布時(shí)間:2021-01-30 09:51:08 來源:億速云 閱讀:158 作者:小新 欄目:編程語言

這篇文章主要介紹了ASP.NET全棧開發(fā)之在MVC中使用服務(wù)端驗(yàn)證的示例,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

在Action里調(diào)用驗(yàn)證器來進(jìn)行驗(yàn)證,像這樣。

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

很可惡,如果我需要驗(yàn)證,我需要在每一個(gè)Action 里像這樣寫,一次實(shí)驗(yàn)也就罷了,如果真要在每個(gè)Action里像這樣干,我想到時(shí)候你一定會(huì)很討厭這些代碼的。至少我是這樣認(rèn)為。所以我很討厭我之前的寫法。

現(xiàn)在我想干嘛呢?我們知道其實(shí)MVC內(nèi)置了一個(gè)數(shù)據(jù)校驗(yàn)。這里不過多介紹它,(偶爾適當(dāng)?shù)恼照蛰喿?,也有許多好處的)。這里簡單描述下它的用法。

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

和咱們之前那樣寫比起來是精簡了許多,但我還是覺得吧,他還是要在每個(gè)Action 里調(diào)用ModelState.IsValid,雖然只有一個(gè)if,但這不是我想要的,我希望它能像這樣

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

不要影響我正常的編程,而我也不去做哪些重復(fù)的事。

換句話說,其實(shí)就是在執(zhí)行我Action之前就去把數(shù)據(jù)給校驗(yàn)了。

于是我們想到了MVC給我們提供的Filter,OnActionExecuting,打開我們的ControllerEx,在里面重寫OnActionExecuting,他有一個(gè)參數(shù)ActionExecutingContext,通過名字我們大致了解了,這個(gè)參數(shù)是個(gè)Action相關(guān)的上下文,那他一定裝了Action相關(guān)的數(shù)據(jù)

我就不墨跡了,先直接上代碼,其實(shí)這些代碼也只是我剛剛才寫出來的而已,我對這個(gè)參數(shù)也不是很了解,通過一個(gè)一個(gè)去嘗試,慢慢得就試出來了。

 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 里,我們首先定義了一個(gè)existError,用來判斷是否驗(yàn)證失敗的,然后我們遍歷了 filterContext.ActionParameters.Values

在filterContext 里,我們看到ActionParameters 是關(guān)于Action的參數(shù)的,通過調(diào)試我發(fā)現(xiàn),他是一個(gè)集合,其鍵是參數(shù)名,比如拿我們這個(gè)Person來講。

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

filterContext.ActionParameters 集合里就有一個(gè)數(shù)據(jù),其鍵是"model" 值呢 model

ASP.NET全棧開發(fā)之在MVC中使用服務(wù)端驗(yàn)證的示例

所以呢我們通過遍歷filterContext.ActionParameters.Value 就能取出每一個(gè)Action的所有參數(shù)了,而每一個(gè)參數(shù)通過.getType().Name 則能取出他的類型名,比如這里model類型是Person 所以filterContext.ActionParameters["model"].GetType().Name 就是“Person”了。

知道了實(shí)體是什么類型,如何獲取具體驗(yàn)證器呢?想想我們的驗(yàn)證器配置 Person = PersonValidator 那太簡單了,這不是一對一的關(guān)系嘛,但總不可能通過一個(gè)switch 去工廠返回吧,那這樣還需要維護(hù)一個(gè)工廠方法。當(dāng)然不是咯,這就要用到咱.NET 提供的強(qiáng)大反射技術(shù)

有時(shí)候我們有一個(gè)匿名對象,是一個(gè)object的時(shí)候,又不知道它具體是什么類型,如何取它的屬性呢?

我這有一個(gè)方法,他能解決這個(gè)問題。

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

從使用上,傳遞一個(gè)屬性名和對象進(jìn)來,返回一個(gè)object的屬性。

我們看看內(nèi)部都做了些什么。

首先獲取類型,然后獲取執(zhí)行的屬性,誒,這個(gè)屬性可不是真的屬性哦,這個(gè)是PropertyInfo類型,是反射里的數(shù)據(jù)類型,它不是真正的屬性值,但我們?nèi)绻胍@取真正的屬性值怎么辦呢?其實(shí)只需要調(diào)用他的GetValue就行了,他有一個(gè)參數(shù),這個(gè)參數(shù)是指獲取那個(gè)對象上的屬性,于是把object傳進(jìn)去就行。

有了這個(gè)基礎(chǔ),反觀我們的目的,知道了Person,有一個(gè)對象叫ValidatotHub 里面有個(gè)屬性PersonValidator ,所以我們只需要獲取一個(gè)叫ValidatorHub對象里的PersonValidator屬性就行了。(Person是可替換的,是根據(jù)參數(shù)類型來的,前面已經(jīng)解釋過了,這里以Person舉例)

現(xiàn)在有個(gè)問題了,我們?nèi)〉降腜ersonValidator 是一個(gè)object類型的,object類型我可不好使用啊,我們又不能顯示的轉(zhuǎn)換為具體類型,因?yàn)檎l知道具體類型是啥呢。如果寫死了就涼了。那肯定也不能用個(gè)switch來維護(hù)啊,那樣不又增加工作量了嗎。

我們慢慢發(fā)現(xiàn)PersonValidator繼承自AbstractValidator<Person> 很顯然它的基類也需要一個(gè)具體類型,不行,繼續(xù)往上走,誒,發(fā)現(xiàn)了AbstractValidator<T>繼承自IValidator,并且IValidator定義了Validate方法。這不就好了嗎,我as 為IValidator類型,就可以用了。這里使用了(里氏轉(zhuǎn)換原則)。我盡量寫得通俗易懂,也將許多基礎(chǔ)東西提一下,但不肯能面面俱到,所以還是建立在一部分基礎(chǔ)之上的。(當(dāng)然更重要的一點(diǎn)是,通過這次遇到的問題讓我以后在設(shè)計(jì)泛型類結(jié)構(gòu)的時(shí)候,都要去繼承一個(gè)非泛型的接口,如果FluentValidator沒有繼承自IValidator 而只是繼承自IValidator<T>其實(shí)從簡單使用上來講,并沒有什么影響啊,但到了我們剛剛這里,問題就出來了,所以這也是給我們狠狠地上了一課?。?/p>

現(xiàn)在我就可以在這里進(jìn)行驗(yàn)證了,我們知道value 就是那個(gè)model 所以直接對他進(jìn)行驗(yàn)證,驗(yàn)證會(huì)返回一個(gè)ValidationResult類型接下來的事我就不解釋了,相信上一章已經(jīng)講得很清楚了。最后根據(jù)是否存在錯(cuò)誤在進(jìn)行提前處理,如果有錯(cuò)誤的話就直接返回視圖呈現(xiàn)錯(cuò)誤了,連咱們的Action都不執(zhí)行了。好了,到這里咱們昨天講得OnActionExecuted 可以直接Delete拉 。

我們現(xiàn)在把ValidatorTest里的驗(yàn)證代碼都去掉來測試一下。

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

在 ValidatorTest 里打上斷點(diǎn),然后什么都不填,直接提交。

ASP.NET全棧開發(fā)之在MVC中使用服務(wù)端驗(yàn)證的示例ASP.NET全棧開發(fā)之在MVC中使用服務(wù)端驗(yàn)證的示例

斷點(diǎn)沒觸發(fā),但錯(cuò)誤消息已呈現(xiàn)。多試幾次~.

ASP.NET全棧開發(fā)之在MVC中使用服務(wù)端驗(yàn)證的示例ASP.NET全棧開發(fā)之在MVC中使用服務(wù)端驗(yàn)證的示例

同樣沒觸發(fā)。

那我們來一次正確的驗(yàn)證。

ASP.NET全棧開發(fā)之在MVC中使用服務(wù)端驗(yàn)證的示例

斷點(diǎn)觸發(fā)了。并且值都通過了校驗(yàn)

ASP.NET全棧開發(fā)之在MVC中使用服務(wù)端驗(yàn)證的示例

F5放行,最終我們的頁面跳轉(zhuǎn)到了 www.baidu.com。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“ASP.NET全棧開發(fā)之在MVC中使用服務(wù)端驗(yàn)證的示例”這篇文章對大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI