天天看點

艾偉_轉載:ASP.NET MVC資料驗證

關于ASP.NET MVC的驗證,用起來很特别,因為MS的封裝,使人了解起來很費解。也可能很多人都在Scott Guthrie等人寫的一本《ASP.NET MVC 1.0》書中,見過NerdDinner項目中對Dinner對象修改和添加的時的資料驗證。但有許多封裝的地方,不知道是怎樣的工作原理,今天研究了,拿出來給大家分享一下。

資料庫還是上一篇blog中的庫與表,同樣的方法來建立news表的實體類,在自動生成的news這個實體類中,我們發現有一個特殊的分部方法:

partial void OnValidate(System.Data.Linq.ChangeAction action);

這個方法沒有實作,我們根據C#的文法知道,如果分部類中的分部方法,沒有實作的話,調用和定議的地方都不會起什麼作用。現在,我們要去完善這個方法,讓它“用”起來。

首先,人産在Models中建立news類的另一部分,代碼如下:

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

Code

 1

艾偉_轉載:ASP.NET MVC資料驗證

 public partial  class news

 2

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

{

 3

艾偉_轉載:ASP.NET MVC資料驗證

        partial void OnValidate(System.Data.Linq.ChangeAction action)

 4

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

 5

艾偉_轉載:ASP.NET MVC資料驗證

            if (!IsValid)

 6

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

 7

艾偉_轉載:ASP.NET MVC資料驗證

                throw new ApplicationException("驗證内容項出錯!");

 8

艾偉_轉載:ASP.NET MVC資料驗證

            }

 9

艾偉_轉載:ASP.NET MVC資料驗證

        }

10

艾偉_轉載:ASP.NET MVC資料驗證

        public bool IsValid

11

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

12

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

            get 

艾偉_轉載:ASP.NET MVC資料驗證

{ return (GetRuleViolations().Count() == 0); }

13

艾偉_轉載:ASP.NET MVC資料驗證

14

艾偉_轉載:ASP.NET MVC資料驗證

        public IEnumerable<RuleViolation> GetRuleViolations()

15

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

16

艾偉_轉載:ASP.NET MVC資料驗證

            if (String.IsNullOrEmpty(this.title .Trim () ))

17

艾偉_轉載:ASP.NET MVC資料驗證

                yield return new RuleViolation("題目步能為空!", "題目");

18

艾偉_轉載:ASP.NET MVC資料驗證

            if (String.IsNullOrEmpty(this.contents .Trim ()))

19

艾偉_轉載:ASP.NET MVC資料驗證

                yield return new RuleViolation("内容不能為空!", "内容");          

20

艾偉_轉載:ASP.NET MVC資料驗證

            yield break;

21

艾偉_轉載:ASP.NET MVC資料驗證

22

艾偉_轉載:ASP.NET MVC資料驗證

    }

23

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

/**//// 

24

艾偉_轉載:ASP.NET MVC資料驗證

    /// 規則資訊類

25

艾偉_轉載:ASP.NET MVC資料驗證

    /// 

26

艾偉_轉載:ASP.NET MVC資料驗證

    public class RuleViolation

27

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

28

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

        public string ErrorMessage 

艾偉_轉載:ASP.NET MVC資料驗證

{ get; private set; }

29

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

        public string PropertyName 

艾偉_轉載:ASP.NET MVC資料驗證

30

艾偉_轉載:ASP.NET MVC資料驗證

31

艾偉_轉載:ASP.NET MVC資料驗證

        public RuleViolation(string errorMessage)

32

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

33

艾偉_轉載:ASP.NET MVC資料驗證

            ErrorMessage = errorMessage;

34

艾偉_轉載:ASP.NET MVC資料驗證

35

艾偉_轉載:ASP.NET MVC資料驗證

36

艾偉_轉載:ASP.NET MVC資料驗證

        public RuleViolation(string errorMessage, string propertyName)

37

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

38

艾偉_轉載:ASP.NET MVC資料驗證

39

艾偉_轉載:ASP.NET MVC資料驗證

            PropertyName = propertyName;

40

艾偉_轉載:ASP.NET MVC資料驗證

41

艾偉_轉載:ASP.NET MVC資料驗證

42

艾偉_轉載:ASP.NET MVC資料驗證

在這裡給出這麼多代碼,其實是提前有設計的,因為從業務角度考慮,還不應該寫這部分代碼。RuleViolation類很簡單,就是一個包括了兩個屬性的類(這個類的結構設計是根據後面的ModelState.AddModelError主法來設計的)。

在news分部類中,有一個IsValid的屬性,這個屬性是bool類型的,傳回值取決于GetRuleViolations這個方法,這個方法傳回值是一個IEnumerable類型的,IEnumerable是通過news的幾個屬性是否為空來生成跌代的。如果title或contents為Null或””,就傳回跌代。其實真正的使用者資料的驗證就是在這裡實作,使用者的資料的對與錯,就是一個邏輯,隻要使用者資料不符合規則,就可以 “yield return new RuleViolation("錯誤辨別","錯誤提示資訊!")”;這裡的錯誤碼提示資訊是顯示到用戶端的,是以要處理好友好的提示。

現在驗證使用者資料,生成錯誤清單的工作都做完了,但關鍵是怎麼能讓使用者送出資料時,調用OnValidate。這個問題,先放一下,請記住,上面的代碼,隻要在使用者送出資料時,調用OnValidate,這樣就能得到錯誤集合。

現在,讓我們來處理Cotroller和View層,在Cotroller層,首先來添加index這個Action,代碼如下:

1

艾偉_轉載:ASP.NET MVC資料驗證

public ActionResult Index()

2

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

{           

3

艾偉_轉載:ASP.NET MVC資料驗證

            var NewsList = DCDC.news.Select(newss=>newss);

4

艾偉_轉載:ASP.NET MVC資料驗證

            return View(NewsList );

5

艾偉_轉載:ASP.NET MVC資料驗證

     }

6

艾偉_轉載:ASP.NET MVC資料驗證

這個Action傳回所有news表中的記錄。

對應的View如下:

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">

艾偉_轉載:ASP.NET MVC資料驗證

    Index

艾偉_轉載:ASP.NET MVC資料驗證

asp:Content>

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

    <h2>Indexh2>

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

    <table>

艾偉_轉載:ASP.NET MVC資料驗證

        <tr>

艾偉_轉載:ASP.NET MVC資料驗證

            <th>th>

艾偉_轉載:ASP.NET MVC資料驗證

            <th>

艾偉_轉載:ASP.NET MVC資料驗證

                ID

艾偉_轉載:ASP.NET MVC資料驗證

            th>

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

                title

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

                datetimes

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

                contents

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

                IsValid

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

        tr>

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

            <td>

艾偉_轉載:ASP.NET MVC資料驗證

                 |

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

            td>

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

43

艾偉_轉載:ASP.NET MVC資料驗證

44

艾偉_轉載:ASP.NET MVC資料驗證

45

艾偉_轉載:ASP.NET MVC資料驗證

46

艾偉_轉載:ASP.NET MVC資料驗證

47

艾偉_轉載:ASP.NET MVC資料驗證

48

艾偉_轉載:ASP.NET MVC資料驗證

49

艾偉_轉載:ASP.NET MVC資料驗證

50

艾偉_轉載:ASP.NET MVC資料驗證

51

艾偉_轉載:ASP.NET MVC資料驗證

52

艾偉_轉載:ASP.NET MVC資料驗證

53

艾偉_轉載:ASP.NET MVC資料驗證

54

艾偉_轉載:ASP.NET MVC資料驗證

55

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

56

艾偉_轉載:ASP.NET MVC資料驗證

57

艾偉_轉載:ASP.NET MVC資料驗證

    table>

58

艾偉_轉載:ASP.NET MVC資料驗證

59

艾偉_轉載:ASP.NET MVC資料驗證

    <p>

60

艾偉_轉載:ASP.NET MVC資料驗證

61

艾偉_轉載:ASP.NET MVC資料驗證

    p>

62

艾偉_轉載:ASP.NET MVC資料驗證

63

艾偉_轉載:ASP.NET MVC資料驗證

代碼中,需要我們注意是的   

因為要導航到Edit的View,把以接下來我們建立Edit的Action和View(因為在編輯資料時,要用到驗證,Edit才是我們的重點)。

艾偉_轉載:ASP.NET MVC資料驗證

 public ActionResult Edit(int id)

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

            var list = DCDC.news.Single(newss=>newss.ID ==id);

艾偉_轉載:ASP.NET MVC資料驗證

            return View(list);

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

中的id會被當成參數送到EditController的Edit(int id)的Action,成為Edit方法的實參。

Edit.aspx頁面如下圖:

艾偉_轉載:ASP.NET MVC資料驗證

對應Edit的Action生成view,代碼如下:

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

    編輯

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

    <h2 style ="text-align :left ;">編輯h2>

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

        <fieldset>

艾偉_轉載:ASP.NET MVC資料驗證

            <legend>詳細内容legend>     

艾偉_轉載:ASP.NET MVC資料驗證

            <p>

艾偉_轉載:ASP.NET MVC資料驗證

                <label for="title">标題:label>

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

            p>

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

                <label for="datetimes">時間:label>

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

                <label for="contents">内容:label>

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

                <input type="submit" value="更新" />

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

        fieldset>

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

    <div>

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

    div>

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

如果要單擊“更新”傳回資料新資料,還需要我們寫如下一個Action:

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

[AcceptVerbs(HttpVerbs.Post)]

艾偉_轉載:ASP.NET MVC資料驗證

        public ActionResult Edit(int id,FormCollection formValuews)

艾偉_轉載:ASP.NET MVC資料驗證

        {

艾偉_轉載:ASP.NET MVC資料驗證

            news Sig_news = DCDC.news.Single(newss => newss.ID == id);

艾偉_轉載:ASP.NET MVC資料驗證

            try

艾偉_轉載:ASP.NET MVC資料驗證

            {               

艾偉_轉載:ASP.NET MVC資料驗證

                Sig_news.title = formValuews.GetValue("title").AttemptedValue;

艾偉_轉載:ASP.NET MVC資料驗證

                Sig_news.datetimes = DateTime.Parse(formValuews.GetValue("datetimes").AttemptedValue);

艾偉_轉載:ASP.NET MVC資料驗證

                Sig_news.contents = formValuews.GetValue("contents").AttemptedValue;

艾偉_轉載:ASP.NET MVC資料驗證

                DCDC.SubmitChanges();

艾偉_轉載:ASP.NET MVC資料驗證

                return RedirectToAction("Index");

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

            catch

艾偉_轉載:ASP.NET MVC資料驗證

            {

艾偉_轉載:ASP.NET MVC資料驗證

                foreach (var v in Sig_news.GetRuleViolations())

艾偉_轉載:ASP.NET MVC資料驗證

                {

艾偉_轉載:ASP.NET MVC資料驗證

                    ModelState.AddModelError(v.PropertyName,v.ErrorMessage);

艾偉_轉載:ASP.NET MVC資料驗證

                }

艾偉_轉載:ASP.NET MVC資料驗證

                return View(Sig_news);

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

這個Edit的Action是使用者送出返來更新資料庫的,我們可以從formValuews得到使用者在頁面上更新的資料,來更新Sig_news對象,然後調用DCDC.SubmitChanges();去更新資料庫,如果沒有民常,會導航到index.aspx頁面。如果發生異常,就會運作到catch裡。如果還記得,在本文的前半部分,我們說到OnValidate,是資料在送出時應該驗證,但在這裡,我們并沒有顯示的調用OnValidate這個方法,但實際運作中,我們發現,這個方法被執行了,如果我們建立跟蹤,把斷點設在DCDC.SubmitChanges();如果我們資料有民常,會發現當DCDC.SubmitChanges();執行完後就會跳到partial void OnValidate(System.Data.Linq.ChangeAction action)這個方法,這是怎麼做到的呢?我們猜測,一定是在資料送出時,調用OnValidate這個方法。為了找到它們的關系,隻好用Reflector.exe來“探測”一下了(Reflector.exe的用法就不說了)。

SubmitChanges方法是DataContext的一個方法,這個類位于System.Data.Linq命空間下,用Reflector.exe打開SubmitChanges,看到this.SubmitChanges(ConflictMode.FailOnFirstConflict);定位這個方法,可以看到new ChangeProcessor(this.services, this).SubmitChanges(failureMode);定位查找會發現ValidateAll(orderedList);在這個方法中,多處看到 SendOnValidate(obj2.Type, obj2, ChangeAction.Insert);這個方法,再定位,有這樣一行代碼 type.OnValidateMethod.Invoke(item.Current, new object[] { changeAction });這裡,正是通過反射調用了OnValidate這個方法。這樣我們就找到了SubmitChanges執行時調用OnValidate的方法了(其不用調用OnValidate也可以驗證使用者資料,隻需要寫個方法,在SubmitChanges 送出以前執行就可以達到同樣效果)。同時,當發生異常時,OnValidate會抛出一個Application的異常,這裡會被public ActionResult Edit(int id,FormCollection formValuews)方法中的Catch捕獲到,就執行如下代碼:

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

foreach (var v in Sig_news.GetRuleViolations())

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

                    this.ModelState.AddModelError(v.PropertyName,v.ErrorMessage);

艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證
艾偉_轉載:ASP.NET MVC資料驗證

這行代碼的意思是把錯誤的資訊,以鍵值的方式放入ModelState中,ModelState是一個ModelStateDictionary類型,這個類型實作了IDictionary, ICollection>, IEnumerable>, IEnumerable這些接口(這裡要注意,ModelState是目前對象的一個屬性,并且它的AddModelError方法的第一個參數key有其獨特的作用)。處理完異常後,還是傳回目前頁面。這時你會發現,在頁面的   發生了變化,把我們錯誤的地方去提示出來了,這裡就是,為什麼我們把錯誤資訊放到ModelState中,而錯誤則顯示在了Html.ValidationSummary中了呢?并且發生錯誤的資料後會加上了一個紅色的“*”,這是怎麼樣做到的呢?

再次利用Reflector.exe,檢視Html.ValidationSummary方法和Html.ValidationMessage方法,會發現它們顯示的資料是從ModelState 中擷取的,如果ModelState 這個集合中沒有資料,Html.ValidationSummary和Html.ValidationMessage就傳回空,如果發生異常,this.ModelState中有子項,就會通過Html.ValidationSummary和Html.ValidationMessage在頁面頁上顯示出來。因為Html.ValidationMessage在頁面上有多個,是以在this.ModelState.AddModelError(v.PropertyName,v.ErrorMessage);方法中的v.PropertyName就有了用處了,這個值要與中的第一個參數對應,這樣才能起到作用,顯示出第二個參數“*”。

這樣一來,就達到了ASP.NET MVC的資料驗證。由于ASPNET MVC 驗證捌的彎比較多,是以下來用個圖來說明一下。

艾偉_轉載:ASP.NET MVC資料驗證