天天看點

ASP.NETMVC Model驗證(三)

ASP.NETMVC Model驗證(三)

前言

上篇中說到在MVC架構中預設的Model驗證是在哪裡驗證的,還講到DefaultModelBinder類型的内部執行的示意圖,讓大家可以看到預設的Model驗證是在哪個具體的方法中來執行的,本篇的主題就是模拟一下預設的實作,自定義個Model綁定器繼承自DefaultModelBinder類型,并且重寫某些個重要的方法。

Model驗證

Model驗證簡單運用示例

ModelValidator使用生成過程

自定義實作DefaultModelBinder進行驗證

自定義ModelValidatorProvider 和ModelValidator 

ValidationAttribute特性類使用

自定義ValidationAttribute特性類的示例實作

以下用到的示例正是修改自ASP.NET MVC Model驗證(一)篇幅中的示例,這裡就不多說什麼了,開始直接貼代碼。

首先是ViewModel的定義,代碼1-1。

代碼1-1

1

2

3

4

5

6

7

8

9

10

11

<code>namespace</code> <code>MvcApplication.Models</code>

<code>{</code>

<code>    </code><code>public</code> <code>class</code> <code>RegistrationInformation</code>

<code>    </code><code>{</code>

<code>        </code><code>public</code> <code>string</code> <code>ID { </code><code>get</code><code>; </code><code>set</code><code>; }</code>

<code>        </code><code>public</code> <code>string</code> <code>UserID { </code><code>get</code><code>; </code><code>set</code><code>; }</code>

<code>        </code><code>public</code> <code>string</code> <code>Password1 { </code><code>get</code><code>;</code><code>set</code><code>; }</code>

<code>        </code><code>public</code> <code>string</code> <code>Password2 { </code><code>get</code><code>;</code><code>set</code><code>; }</code>

<code>        </code><code>public</code> <code>string</code> <code>Name { </code><code>get</code><code>; </code><code>set</code><code>; }</code>

<code>    </code><code>}</code>

<code>}</code>

控制器的定義,代碼1-2:

代碼1-2

<code>    </code><code>public</code> <code>class</code> <code>ModelValidatorController: Controller</code>

<code>        </code><code>public</code> <code>ActionResult Index()</code>

<code>        </code><code>{</code>

<code>            </code><code>returnView(</code><code>new</code> <code>Models.RegistrationInformation());</code>

<code>        </code><code>}</code>

<code>        </code><code>public</code> <code>ActionResult ModelValidator(RegistrationInformation regInfo)</code>

<code>            </code><code>returnView(regInfo);</code>

控制器方法對應視圖定義,代碼1-3:

代碼1-3-1

Index視圖

@model MvcApplication.Models.RegistrationInformation

@{

    ViewBag.Title = "Index";

}

&lt;h2&gt;Index&lt;/h2&gt;

@using (Html.BeginForm("ModelValidator","ModelValidator"))

{

    &lt;p&gt;使用者注冊ID:@Html.EditorFor(m=&gt;m.ID)&lt;/p&gt;

    &lt;p&gt;使用者名:@Html.EditorFor(m=&gt;m.UserID)&lt;/p&gt;

    &lt;p&gt;登入密碼:@Html.EditorFor(m=&gt;m.Password1)&lt;/p&gt;

    &lt;p&gt;再次輸入域密碼:@Html.EditorFor(m=&gt;m.Password2)&lt;/p&gt;

    &lt;p&gt;姓名:@Html.EditorFor(m=&gt;m.Name)&lt;/p&gt;

    &lt;input type="submit" value="送出" /&gt;

代碼1-3-2

ModelValidator視圖

    ViewBag.Title = "ModelValidator";

&lt;h2&gt;ModelValidator&lt;/h2&gt;

@Html.ValidationSummary(true)

&lt;p&gt;使用者注冊ID:@Html.EditorFor(m =&gt; m.ID)

@Html.ValidationMessageFor(m=&gt;m.ID)

&lt;/p&gt;

&lt;p&gt;使用者名:@Html.EditorFor(m =&gt; m.UserID)

@Html.ValidationMessageFor(m=&gt;m.UserID)&lt;/p&gt;

&lt;p&gt;登入密碼:@Html.EditorFor(m =&gt; m.Password1)

@Html.ValidationMessageFor(m=&gt;m.Password1)

&lt;p&gt;再次輸入域密碼:@Html.EditorFor(m =&gt; m.Password2)

@Html.ValidationMessageFor(m=&gt;m.Password2)

&lt;p&gt;姓名:@Html.EditorFor(m=&gt;m.Name)&lt;/p&gt;

前面所示的就是把示例示範所需的定義好,這個時候運作會發現,隻不過是一個頁面傳值而已,什麼都沒有發生。現在我們來定義一下自定義的Model綁定器繼承自DefaultModelBinder類型。

代碼1-4

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

<code>    </code><code>public</code> <code>class</code> <code>MyCustomDefaultModelBinder: DefaultModelBinder</code>

<code>        </code><code>protectedoverride voidSetProperty(ControllerContextcontrollerContext, ModelBindingContextbindingContext, PropertyDescriptorpropertyDescriptor, </code><code>object</code> <code>value)</code>

<code>            </code><code>base</code><code>.SetProperty(controllerContext,bindingContext, propertyDescriptor, value);</code>

<code> </code> 

<code>            </code><code>switch</code><code>(propertyDescriptor.Name)</code>

<code>            </code><code>{</code>

<code>                </code><code>case</code><code>"ID"</code><code>:</code>

<code>                    </code><code>if</code><code>(</code><code>string</code><code>.IsNullOrEmpty((</code><code>string</code><code>)value)|| (</code><code>string</code><code>)value == </code><code>""</code><code>)</code>

<code>                    </code><code>{</code>

<code>                       </code><code>bindingContext.ModelState.AddModelError(</code><code>"ID"</code><code>,</code><code>"請輸入ID,ID不能為空!"</code><code>);</code>

<code>                    </code><code>}</code>

<code>                    </code><code>break</code><code>;</code>

<code>                </code><code>case</code><code>"UserID"</code><code>:</code>

<code>                       </code><code>bindingContext.ModelState.AddModelError(</code><code>"UserID"</code><code>,</code><code>"請輸入使用者賬戶,使用者賬戶不能為空!"</code><code>);</code>

<code>                </code><code>case</code><code>"Password1"</code><code>:</code>

<code>                       </code><code>bindingContext.ModelState.AddModelError(</code><code>"Password1"</code><code>,</code><code>"請輸入登入密碼,登入密碼不能為空!"</code><code>);</code>

<code>                </code><code>case</code><code>"Password2"</code><code>:</code>

<code>                        </code><code>bindingContext.ModelState.AddModelError(</code><code>"Pssword2"</code><code>, </code><code>"請再次輸入密碼,密碼不能為空!"</code><code>);</code>

<code>                </code><code>case</code><code>"Name"</code><code>:</code>

<code>            </code><code>}</code>

<code>        </code><code>protectedoverride voidOnModelUpdated(ControllerContextcontrollerContext, ModelBindingContextbindingContext)</code>

<code>            </code><code>base</code><code>.OnModelUpdated(controllerContext,bindingContext);</code>

<code>            </code><code>Models.RegistrationInformationregInfo = bindingContext.Model </code><code>as</code> <code>Models.RegistrationInformation;</code>

<code>            </code><code>if</code><code>(bindingContext.ModelState[</code><code>"Password1"</code><code>].Errors.Count== 0 &amp;&amp; bindingContext.ModelState[</code><code>"Password2"</code><code>].Errors.Count== 0)</code>

<code>                </code><code>if</code><code>(regInfo.Password1 != regInfo.Password2)</code>

<code>                </code><code>{</code>

<code>                   </code><code>bindingContext.ModelState.AddModelError(</code><code>"Password2"</code><code>,</code><code>"請重新輸入密碼,與上次輸入密碼不同"</code><code>);</code>

<code>                </code><code>}</code>

<code>            </code><code>if</code><code>(</code><code>string</code><code>.Compare(regInfo.Name, </code><code>"jinyuan"</code><code>, </code><code>true</code><code>)==0)</code>

<code>               </code><code>bindingContext.ModelState.AddModelError(</code><code>""</code><code>,</code><code>"您輸入的名稱違法了,立即更改不然查水表"</code><code>);</code>

代碼1-4中,我們重寫了SetProperty()方法,從上篇的知識中得知,這個方法是在PropertyDescriptor類型的集合中周遊執行的,是以每次進入方法内部的隻是個Model屬性,而在SetProperty()方法内部的Model驗證判斷邏輯和ASP.NETMVC Model驗證(一)篇幅的一樣。

而在OnModelUpdated()方法中,我們首先擷取了示例代碼1-1中定義的ViewModel類型執行個體,這裡有的朋友可能會問為什麼不在SetProperty()方法中也這樣使用,而是使用PropertyDescriptor類型的參數來進行驗證操作,因為在SetProperty()方法執行的期間并沒有對ViewModel完全的指派,是以不能那樣直接擷取執行個體來使用。接着上面的說,在此之後從目前的綁定上下文的ModelState屬性中擷取判斷密碼1和密碼2是否存在屬性驗證級的錯誤資訊,沒有的話将會對它們進行等值驗證,正如上面代碼所示的那樣,随之驗證Name的時候我将錯誤資訊添加的鍵值為””,這表示預設為Model級驗證錯誤資訊。

所需要做的驗證都做完了,注冊我們的自定義綁定器到系統中,在Global.asax檔案的Application_Start()中添加代碼1-5.

代碼1-5

<code>ModelBinders.Binders.Add(</code><code>typeof</code><code>(Models.RegistrationInformation),</code><code>new</code> <code>Binders.MyCustomDefaultModelBinder());</code>

最後我們看一下效果圖,圖1表示為起初展示的頁面,在我輸入一部分的資訊過後,點選送出過後頁面會跳轉到圖2,并且執行完驗證顯示出驗證後的錯誤資訊。

圖1

<a href="http://s3.51cto.com/wyfs02/M01/3B/A2/wKiom1O-krOSb5L2AAEL1TlPDiQ637.jpg" target="_blank"></a>

圖2

<a href="http://s3.51cto.com/wyfs02/M00/3B/A2/wKioL1O-krLgdMM1AAHGT3AcGlE253.jpg" target="_blank"></a>

大家可以動手試一試,到這裡說明了一種驗證方式,将在下篇為大家講解MVC架構提供給我們的正兒八經用來執行驗證的類型的一些相關類型,以及一些簡單的示例,這樣我們就不在使用Model綁定器來執行驗證了,看起來綁定器有點不務正業。

     本文轉自jinyuan0829 51CTO部落格,原文連結:http://blog.51cto.com/jinyuan/1436861,如需轉載請自行聯系原作者