艾伟_转载: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類的另一部分,代碼如下:
Code?1?public?partial??class?news
?2????{
?3????????partial?void?OnValidate(System.Data.Linq.ChangeAction?action)
?4????????{
?5????????????if?(!IsValid)
?6????????????{
?7????????????????throw?new?ApplicationException("驗證內容項出錯!");
?8????????????}
?9????????}
10????????public?bool?IsValid
11????????{
12????????????get?{?return?(GetRuleViolations().Count()?==?0);?}
13????????}
14????????public?IEnumerable<RuleViolation>?GetRuleViolations()
15????????{
16????????????if?(String.IsNullOrEmpty(this.title?.Trim?()?))
17????????????????yield?return?new?RuleViolation("題目步能為空!",?"題目");
18????????????if?(String.IsNullOrEmpty(this.contents?.Trim?()))
19????????????????yield?return?new?RuleViolation("內容不能為空!",?"內容");??????????
20????????????yield?break;
21????????}
22????}
23/**////?
24????///?規則信息類
25????///?
26????public?class?RuleViolation
27????{
28????????public?string?ErrorMessage?{?get;?private?set;?}
29????????public?string?PropertyName?{?get;?private?set;?}
30
31????????public?RuleViolation(string?errorMessage)
32????????{
33????????????ErrorMessage?=?errorMessage;
34????????}
35
36????????public?RuleViolation(string?errorMessage,?string?propertyName)
37????????{
38????????????ErrorMessage?=?errorMessage;
39????????????PropertyName?=?propertyName;
40????????}
41????}
42
?
在這里給出這么多代碼,其實是提前有設計的,因為從業務角度考慮,還不應該寫這部分代碼。RuleViolation類很簡單,就是一個包括了兩個屬性的類(這個類的結構設計是根據后面的ModelState.AddModelError主法來設計的)。
在news分部類中,有一個IsValid的屬性,這個屬性是bool類型的,返回值取決于GetRuleViolations這個方法,這個方法返回值是一個IEnumerable類型的,IEnumerable是通過news的幾個屬性是否為空來生成跌代的。如果title或contents為Null或””,就返回跌代。其實真正的用戶數據的驗證就是在這里實現,用戶的數據的對與錯,就是一個邏輯,只要用戶數據不符合規則,就可以 “yield return new RuleViolation("錯誤標識","錯誤提示信息!")”;這里的錯誤碼提示信息是顯示到客戶端的,所以要處理好友好的提示。
現在驗證用戶數據,生成錯誤列表的工作都做完了,但關鍵是怎么能讓用戶提交數據時,調用OnValidate。這個問題,先放一下,請記住,上面的代碼,只要在用戶提交數據時,調用OnValidate,這樣就能得到錯誤集合。
現在,讓我們來處理Cotroller和View層,在Cotroller層,首先來添加index這個Action,代碼如下:
2????????{???????????
3????????????var?NewsList?=?DCDC.news.Select(newss=>newss);
4????????????return?View(NewsList?);
5?????}
6
這個Action返回所有news表中的記錄。
對應的View如下:
Code?1
?2
?3<asp:Content?ID="Content1"?ContentPlaceHolderID="TitleContent"?runat="server">
?4????Index
?5asp:Content>
?6
?7<asp:Content?ID="Content2"?ContentPlaceHolderID="MainContent"?runat="server">
?8
?9????<h2>Indexh2>
10
11????<table>
12????????<tr>
13????????????<th>th>
14????????????<th>
15????????????????ID
16????????????th>
17????????????<th>
18????????????????title
19????????????th>
20????????????<th>
21????????????????datetimes
22????????????th>
23????????????<th>
24????????????????contents
25????????????th>
26????????????<th>
27????????????????IsValid
28????????????th>
29????????tr>
30
31????
32????
33????????<tr>
34????????????<td>
35?????????????????|
36????????????????
37????????????td>
38????????????<td>
39????????????????
40????????????td>
41????????????<td>
42????????????????
43????????????td>
44????????????<td>
45????????????????
46????????????td>
47????????????<td>
48????????????????
49????????????td>
50????????????<td>
51????????????????
52????????????td>
53????????tr>
54????
55????
56
57????table>
58
59????<p>
60????????
61????p>
62asp:Content>
63
?
代碼中,需要我們注意是的???
因為要導航到Edit的View,把以接下來我們創建Edit的Action和View(因為在編輯數據時,要用到驗證,Edit才是我們的重點)。
1?public?ActionResult?Edit(int?id)2????????{
3????????????var?list?=?DCDC.news.Single(newss=>newss.ID?==id);
4????????????return?View(list);
5?????}
6
<%= Html.ActionLink("Edit", "Edit", new { id=item.ID }) %>
中的id會被當成參數送到EditController的Edit(int id)的Action,成為Edit方法的實參。
Edit.aspx頁面如下圖:
對應Edit的Action生成view,代碼如下:
Code?1
?2<asp:Content?ID="Content1"?ContentPlaceHolderID="TitleContent"?runat="server">
?3????編輯
?4asp:Content>
?5<asp:Content?ID="Content2"?ContentPlaceHolderID="MainContent"?runat="server">
?6????<h2?style?="text-align?:left?;">編輯h2>
?7????
?8????
10????????<fieldset>
11????????????<legend>詳細內容legend>?????
12????????????<p>
13????????????????<label?for="title">標題:label>
14????????????????
15????????????????
16????????????p>
17????????????<p>
18????????????????<label?for="datetimes">時間:label>
19????????????????
20?????????????????
21????????????p>
22????????????<p>
23????????????????<label?for="contents">內容:label>
24????????????????
25????????????????
26????????????p>
27????????????<p>
28????????????????<input?type="submit"?value="更新"?/>
29????????????p>
30????????fieldset>
31????
32????<div>
33????????
34????div>
35
36asp:Content>
37
?
如果要單擊“更新”返回數據新數據,還需要我們寫如下一個Action:
Code?1[AcceptVerbs(HttpVerbs.Post)]
?2????????public?ActionResult?Edit(int?id,FormCollection?formValuews)
?3????????{
?4????????????news?Sig_news?=?DCDC.news.Single(newss?=>?newss.ID?==?id);
?5????????????try
?6????????????{???????????????
?7????????????????Sig_news.title?=?formValuews.GetValue("title").AttemptedValue;
?8????????????????Sig_news.datetimes?=?DateTime.Parse(formValuews.GetValue("datetimes").AttemptedValue);
?9????????????????Sig_news.contents?=?formValuews.GetValue("contents").AttemptedValue;
10????????????????DCDC.SubmitChanges();
11????????????????return?RedirectToAction("Index");
12????????????}
13????????????catch
14????????????{
15????????????????foreach?(var?v?in?Sig_news.GetRuleViolations())
16????????????????{
17????????????????????ModelState.AddModelError(v.PropertyName,v.ErrorMessage);
18????????????????}
19????????????????return?View(Sig_news);
20????????????}
21????????}
22
?
這個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捕獲到,就執行如下代碼:
1foreach?(var?v?in?Sig_news.GetRuleViolations())
2????????????????{
3????????????????????this.ModelState.AddModelError(v.PropertyName,v.ErrorMessage);
4????????????????}
5????????????????return?View(Sig_news);
6
?
這行代碼的意思是把錯誤的信息,以鍵值的方式放入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 驗證捌的彎比較多,所以下來用個圖來說明一下。
源碼:/Files/axzxs2001/MvcCompany.rar
轉載于:https://www.cnblogs.com/waw/archive/2011/08/29/2157134.html
總結
以上是生活随笔為你收集整理的艾伟_转载:ASP.NET MVC数据验证的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 艾伟_转载:使用LINQ to SQL更
- 下一篇: win7xp双系统引导修复工具