ASP.Net MVC開發基礎學習筆記(4):校驗、AJAX與過濾器

發表於2015-03-17

一、校驗 — 表單不是你想提想提就能提

1.1 DataAnnotations(資料註解)

位於 System.ComponentModel.DataAnnotations 名稱空間中的特性指定對資料模型中的各個欄位的驗證。這些特性用於定義常見的驗證模式,例如範圍檢查和必填欄位。而 DataAnnotations 特性使 MVC 能夠提供客戶端和伺服器驗證檢查,使你無需進行額外的編碼來控制資料的有效

通過為模型類增加資料描述的 DataAnnotations ,我們可以容易地為應用程式增加驗證的功能。DataAnnotations 允許我們描述希望應用在模型屬性上的驗證規則,ASP.NET MVC 將會使用這些 DataAnnotations ,然後將適當的驗證資訊返回給使用者。

在DataAnnotations為我們所提供的眾多內建驗證特性中,用的最多的其中的四個是:

(0)[DisplayName]:顯示名 – 定義表單欄位的提示名稱

(1)[Required] :必須 – 表示這個屬性是必須提供內容的欄位

(2)[StringLength]:字串長度 – 定義字串型別的屬性的最大長度

(3)[Range]:範圍 – 為數字型別的屬性提供最大值和最小值

(4)[RegularExpression]:正規表示式 – 指定動態資料中的資料欄位值必須與指定的正規表示式匹配

1.2 使用DataAnnotations為Model進行校驗

假設我們的Model中有一個UserInfo的實體,其定義如下:

UserInfo的屬性很簡單,只有三個:Id,UserName和Age三個欄位;現在我們可以為其增加驗證特性,看看其為我們提供的強大的校驗功能。

(1)非空驗證

新增特性:

驗證效果:

(2)字串長度驗證

新增特性:

驗證效果:

(3)範圍驗證

新增特性:

驗證效果:

(4)正規表示式驗證

新增特性:驗證使用者輸入的是否是數字,正規表示式匹配

驗證效果:

(5)瀏覽所生成的HTML程式碼

從上圖可以看出,我們在瀏覽器端的校驗都是通過為html標籤設定自定義屬性來實現的,我們在Model中為其新增的各種校驗特性,都會在客戶端生成一個特定的屬性,例如:data-val-length-max=“5”與data-val-length=”*長度必須小於5″對應[StringLength(5, ErrorMessage = “*長度必須小於5”)]。然後,通過jquery validate在客戶端每次提交之前進行校驗,如果校驗匹配中有不符合規則的,則將message顯示在一個特定的span標籤(class=”field-validation-valid”)內,並阻止此次表單提交操作。

1.3 使用DataAnnotations的注意事項

(1)首先,要確保需要進行校驗的頁面中引入了指定的幾個js檔案:

當然,jquery庫的js檔案也是必須的,而且在上面這兩個js之前引入;

(2)在 Web.config 的appSettings中,已經預設支援了客戶端驗證(MVC3.0及更高版本中預設支援,MVC2.0則需要修改一下):

PS:Unobtrusive Javascript有三層含義:

一是在HTML程式碼中不會隨意的插入Javsscript程式碼,只在標籤中加一些額外的屬性值,然後被引用的指令碼檔案識別和處理;

二是通過指令碼檔案所增加的功能是一種漸進式的增強,當客戶端不支援或禁用了Javsscript時網頁所提供的功能仍然能夠實現,只是使用者體驗會降低;

三是能夠相容不同的瀏覽器。

(3)在Action中如果要對客戶端是否通過了校驗進行驗證,可以通過以下程式碼實現:

如果通過校驗,則ModelState的IsValid屬性(bool型別)會變為true,反之則為false。

二、ASP.Net MVC下的兩種AJAX方式

2.1 使用JQuery AJAX方式

首先,在ASP.Net MVC中使用此種方式跟普通的WebForm的開發方式是一致的,需要注意的是:Url地址不同->請求的是Controller下的Action,例如在WebForm中請求的url通常是/Ajax/UserHandler.ashx,而在MVC中請求的url通常為:/User/GetAll。

例如,我們在一個View中新增一個按鈕,用於使用AJAX獲取一個伺服器端的時間:

在Home控制器中增加一個用於返回時間的Action:

在View中增加一段JQuery程式碼,為btnJQuery按鈕繫結一個Click事件:

這裡通過JQuery AJAX傳送一個非同步的POST請求,獲取伺服器時間結果,並將其顯示在span標籤內:

至此,一個使用JQuery Ajax的MVC頁面就完成了。但是,這僅是一個最簡單的AJAX示例,在實際開發中往往比較複雜一點。

需要注意的是:

(1)如果你在JQuery AJAX中使用的是get方式的提交,那麼在在使用Json返回JsonResult時注意要將第二個引數設定允許Get提交方式:return Json(“”,JsonRequestBehavior.AllowGet),否則你用get方式是無權執行要請求的Action方法的。

(2)在Ajax開發中要注意Ajax方法體內的引數設定正確,特別是引數名要和Action中的引數名保持一致;

(3)如果在Action中為其設定了[HttpPost]或[HttpGet],那麼提交方式要跟Action打的標籤一致;

2.2 使用Microsoft AJAX方式

在ASP.Net MVC中除了可以使用JQuery AJAX外,Microsoft為我們提供了另一套實用且更簡單的AJAX方案,我們姑且稱其為:Microsoft AJAX方式。

(1)首先:

需要將微軟提供的js指令碼引入到頁面中:其實就是jquery.unobtrusive-ajax.js

確保在Web.config中啟用了Unobtrusive JavaScript

(2)其次,使用Ajax.BeginForm方法構造一個form表單:

這裡需要注意的是:

①Ajax.BeginForm沒有提供閉合的方法,需要使用Using配合關閉;

②AjaxOptions引數的設定:

HttpMethod代表此次AJAX請求到底是POST方式還是GET方式?這裡是POST方式;

Confirm代表點選提交按鈕後提出的確認對話方塊,並給出使用者給定的提示語,這裡是:您確定要提交?

InsertionMode代表請求獲得後的資料是要替換還是追加,一般選擇替換,即Replace;

UpdateTargetId代表需要替換的div標籤的Id,這裡是一個span標籤,代表需要顯示的資訊都顯示在這個span內;

OnSuccess代表請求成功後所需要執行的回撥方法,是一個js方法,可以自定義,這裡是一個function afterSuccess()的方法;

LoadingElementId=”loading”是一個很有意思的屬性,代表在ajax請求期間為了提供良好的使用者體驗,可以給出一個正在載入中的提示,而這個LoadingElementId則代表一個提示的div區域的Id。這裡主要是指id為loading的這個div,其中有一張gif圖片及一句話:正在獲取中,請稍等…的提示。

為了顯示載入提示的效果,我們人為地修改一下Action方法,使用Thread.Sleep(3000)來延遲一下請求返回時間

好了,現在我們可以看一下效果如何:

到此,我們的Microsoft AJAX就算完成了一個最簡單的Demo了。那麼,我們不禁想知道Microsoft AJAX是怎麼做到的?跟校驗一樣,我們瀏覽一下生成的form表單就知道了:

原來我們在AjaxOptions中所設定的引數也被解析成了form的自定義屬性,它們的對應關係如下:

三、為AOP而生 — ASP.Net MVC預設的過濾器

3.1 過濾器初步

  大一點的專案總會有相關的AOP面向切面的元件,而MVC(特指:Asp.Net MVC,以下皆同)專案中Action在執行前或者執行後我們想做一些特殊的操作(比如身份驗證,日誌,異常,行為擷取等),而不想讓MVC開發人員去關心和寫這部分重複的程式碼。那麼,我們可以通過AOP擷取實現,而在MVC專案中我們就可以直接使用它提供的Filter的特性幫我們解決,不用自己實現複雜的AOP了。
AOP:Aspect Oriented Programming(AOP)是較為熱門的一個話題。AOP,國內大致譯作“面向切面程式設計”。針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。
  利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。主要的功能是:日誌記錄,效能統計,安全控制,事務處理,異常處理等等。

3.2 微軟提供的幾種預設過濾器

微軟預設為我們提供了四種型別的過濾器(Filter),如下圖所示:

這裡,我們主要來看看ActionFilter(Action過濾器)和ExceptionFilter(異常過濾器)的使用:

(1)Action Filter

ActionFilterAttribute預設實現了IActionFilter和IResultFilter。而ActionFilterAttribute是一個Abstract的型別,所以不能直接使用,因為它不能例項化,所以我們想使用它必須繼承一下它然後才能使用。

①因此,我們首先在Models中新建一個類,取名為:MyActionFilterAttribute(以Attribute結尾比較符合編碼規範),並使其繼承自ActionFilterAttribute,然後重寫基類所提供的虛方法:

這裡我們重寫了四個虛方法,他們各自代表了在Action執行之前和之後需要執行的業務邏輯,以及在Result執行之前和之後需要執行的業務邏輯。這裡的Result主要是指我們在Action中進行return 語句返回結果時(例如:return Content(“Hello Filter!”);),之前和之後要執行的邏輯處理。

比如:我們想要在每個Action執行之前進行使用者是否登入的校驗,可以在OnActionExecuting中判斷使用者Session是否存在,如果存在則繼續執行Action的具體業務程式碼,如果不存在則重定向頁面到登陸頁,後邊的Action業務程式碼不再執行。

②現在有了自定義的過濾器,我們怎麼將其應用到Action中呢?這裡有三種方式:

一是給某個控制器的某個Action指定此Filter:

二是給某個控制器的所有Action指定此Filter:

但是,要注意的是:如果既給Controller指定了Filter,又給該Controller中的某個Action指定了Filter,那麼具體的這個Action以離其定義最近的Filter為準,也就是一個優先順序的順序問題:Action的Filter優先順序高於Controller的Filter。

三是給此專案中的所有控制器即全域性指定此Filter:在App_Start中更改FilterConfig類,此種方式優先順序最低

③現在我們來看看具體的效果:

可以看到,我們的/Home/Filter這個Action中只有兩句程式碼,一句Response.Write,另一句是return Content();在Response.Write之前執行了OnActionExecuting的過濾器方法,之後則執行了OnActionExecuted的過濾器方法;我們剛剛說了,在Action中的return語句代表了Result,那麼在Result之前執行了OnResultExecuting過濾器方法,之後則執行了OnResultExecuted過濾器方法。這裡僅僅是為了展示,在實際開發中是需要寫一些具體的業務邏輯處理的,例如:判斷使用者的登入狀態,記錄使用者的操作日誌等等。

(2)Exception Filter

①同樣,在Models中新建一個類,取名為:MyExceptionFilterAttribute,並使其繼承自HandleErrorAttribute。

這裡,重寫基類的OnException方法,這裡僅僅為了演示效果,沒有對異常進行處理。在實際開發中,需要獲取異常物件,並將其記錄至日誌中。例如,下面一段程式碼:

②有了異常過濾器,我們怎麼來應用到專案中呢?答案也在App_Start中,還是在FilterConfig類中,新添一句程式碼進行註冊:

③為了測試,我們新增一個Action,使其能夠出現一個異常:DividedByZero

④當我們測試這個Action時,會發現系統執行了自定義的異常過濾器,將我們的這個請求改為重定向到Index這個Action了。

參考資料

(1)蔣金楠,《ASP.NET MVC下的四種驗證程式設計方式》,http://www.cnblogs.com/artech/p/asp-net-mvc-validation-programming.html

(2)蔣金楠,《ASP.NET MVC下的四種驗證程式設計方式[續篇]》,http://www.cnblogs.com/artech/p/asp-net-mvc-4-validation.html

(3)馬倫,《ASP.NET MVC 2014特供教程》,http://bbs.itcast.cn/thread-26722-1-1.html

(4)w809026418,《MVC中使用 DataAnnotations 進行模型驗證》,http://www.cnblogs.com/haogj/archive/2011/11/16/2251920.html

(5)劉俊峰,《ASP.NET MVC中Unobtrusive Ajax的妙用》,http://www.cnblogs.com/rufi/archive/2012/03/31/unobtrusive-ajax.html

相關文章