預備知識:擴展方法(Extension Method);Asp.net MVC
一般的做法
以修改一篇blog爲例,當我們再輸入框中輸入了修改的內容之後,通過點擊提交按鈕將新的blog內容提交到服務器端,如圖所示,我們可以修改blog的title,body和timestamp三項:
圖 1
我們可能寫出這樣的代碼:
[ControllerAction] public void Save(int id) { BlogDataContext dbBlog = new BlogDataContext(); Post post = dbBlog.Posts.Single(p => p.ID == id);
post.Body = Request.Form["Body"]; post.Title = Request.Form["Title"]; post.Timestamp = DateTime.Parse(Request.Form["Timestamp"]); dbBlog.SubmitChanges(); RedirectToAction(new { action = "Detail", id = post.ID }); }
這段代碼顯示了controller從view的Request中讀取內容,然後更新model。在新的Asp.net模型中,view的內容都放在Request.Form對象中,該對象是一個HttpValueCollection集合。
圖 2
仔細看它裏面存儲的值,實際上就是我們在以前看到的Request.QueryString,只是現在我們不用在Url中顯示地用?來寫出,而是由Asp.net MVC框架幫我們生成,它會自動讀取我們在form中定義的有些元素及其中所包含的內容。下面是一個form的例子,紅色標註的地方可以先忽略:
圖 3
BindingHelperExtension.UpdateFrom讓更新變得更加容易
回到更新blog內容的問題上來,下面的代碼可以完成更新任務:
post.Body = Request.Form["Body"];
post.Title = Request.Form["Title"];
post.Timestamp = DateTime.Parse(Request.Form["Timestamp"]);
但是這樣一個屬性一個屬性地修改Model的值很繁瑣,而且中間涉及到類型轉換。比如上面的DateTime類型的屬性Timestamp,嚴格的說我們應該在更新它的值之前坐類型判斷,空值判斷等等操作。當屬性超過10個甚至更多時,更新屬性的代碼加上類型轉換,錯誤處理等等,代碼的數量就比較打了。那麼有沒有更加簡便的做法呢?實際上在MvcToolkit.dll這個程序集中爲我們提供了一個簡化操作的類,它就是UrlHelper,是一個擴展方法,可以附加到任何的Object類型的對象上。
圖 4
添加對MvcToolkit.dll的引用,並引入名字空間
using System.Web.Mvc.BindingHelpers;
之後我們就可以使用BindingHelpExtension類了。
[ControllerAction] public void Save(int id) { BlogDataContext dbBlog = new BlogDataContext(); Post post = dbBlog.Posts.Single(p => p.ID == id);
post.UpdateFrom(Request.Form);//post.Body = Request.Form["Body"]; //post.Title = Request.Form["Title"]; //post.Timestamp = DateTime.Parse(Request.Form["Timestamp"]);dbBlog.SubmitChanges(); RedirectToAction(new { action = "Detail", id = post.ID }); }
這樣修改一個對象的屬性是不是很簡單呢?毫無疑問,而且這樣還帶來了另外一個好處,如果這個時候Post的屬性變了(屬性名或屬性個數),我們不需要修改Controller的代碼,需要修改的只是View部分。
使用UpdateFrom的前提
UpdateFrom固然很好用,可是需要配合Form的Action來完成,而且它對於view中元素的定義有一定的要求。
Url.Action
先來看看Action。我們爲Form添加Action,注意method屬性是post的,因爲是提交給服務器。
<form action="<%= Url.Action(new {action="Save",id=ViewData.ID}) %>" method="post">
這裏action的語法有一點怪異,實際上它生成後的Url是這樣的:
<form action="/MVCStudy/Blog/Save/10" method="post">
這裏的Url實際上ViewPage的一個屬性,而該屬性又是UrlHelper的一個實例,所以這裏的Url.Action實際上System.Web.Mvc.UrlHelper類的方法Action,該類存在於System.Web.Extension.dll程序集中。
圖 5
至於Url.Action方法生成Url的原理,可以參考Scott的文章“ASP.NET MVC Framework's Routing Engine”
HtmlName——指定HtmlName,updatefrom才能生效。
這裏的HtmlName是指在使用HtmlHelper類來生成html元素時所需要指定的相應的html元素的名字:
圖 6
比如:
圖 7
這裏雖然生成id和name兩個屬性,但是Asp.net MVC使用的"name"。生成這一元素的代碼:
<p class="body"> <%--<%=Html.TextArea("bodyOfBlog",ViewData.Body) %>--%> <%=Html.TextArea("Body",ViewData.Body) %> </p>
注意這裏的HtmlName一定要與對應的model的屬性名一致,否則無法完成更新。上述代碼中註釋掉的代碼行就是這樣一個例子。正確的HtmlName設定,請參考本文圖3。
總結
使用UpdateFrom可以爲我們帶來很多便利,例如類型轉換、空值檢查之類,同時它也使得代碼更加容易維護,因爲在controller中不需要理會model的具體的屬性,充分發揮了Data Banding的作用。讓框架爲我們做更多的事,那麼我們就可以更省事。
如果你的UpdateFrom不起作用,那麼首先應該檢查一下Form的action以及HtmlName的設定是否正確.
引用通告
- 無