ASP.NET全棧開發之在MVC中使用服務端驗證(二)

來源:互聯網
上載者:User
首先聲明,這篇博文是完善.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 去工廠返回吧,那這樣還需要維護一個Factory 方法。當然不是咯,這就要用到咱.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。

好了,小夥伴們還不快去改改代碼造就幸福生活。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.