剛從webform開發轉到mvc,如果說像路由這樣稍微復雜一點的知識點還可以暫時先放一放(前提是默認的路由規則基本滿足大部分需求),那有個問題在快速開發中,我想是必須要當即解決的,那就是webform中的傳值方式是否同樣適用於mvc中。那么本文照舊分兩部分來闡述。接下來先簡單快速地回顧webform中的傳值方式。
Part 1 WebForm中的傳值方式
Form表單傳遞(get/post)
//aspx
<input type="text" id="txtName" name="txtName" runat="server"/>
//aspx.cs
string txtName = Request.Form["txtName"].ToString();
//隱藏域(以html服務器控件為例)
<input type="hidden" id="hdUserId" runat="server" />
hdUserId.Value = "1";
以上僅僅使用文本標簽和隱藏域為例。只要通過Form表單提交的的數據(包含隱藏域),不論是什么標簽。都屬於這種傳值方式。
URL傳遞
1.超鏈接(以html標簽為例):
<a href="Default.aspx?param1=1111¶m2=2222">Go</a>
2.PostBackUrl
<asp:Button ID="btnCheckOut" Text="CheckOut" PostBackUrl="~/Default.aspx?UserId=1" runat="Server" /> //get var userId=Request.QueryString["UserId"]
以上僅以<a>標簽和PostBckUrl帶參數傳遞為例。所有的這些通過url地址欄傳遞參數的都是URL傳值。
內置對象傳遞
1.Response.Redirect
//page1 string url = "Default.aspx?p1=" + p1 + "&p2=" + p1; Response.Redirect(url, false); //page2 var p1 = Request.QueryString["p1"].ToString(); var p2 = Request.QueryString["p2"].ToString();
采取這種方式實際上還是地址欄URL傳值得方式。
2.Server.Transfer\Server.Execute
//Default.aspx <input type="text" id="txtName" runat="server" /> //Default.aspx.cs Server.Transfer("~/Default2.aspx", true); Server.Execute("~/Default2.aspx", true); //Default.aspx.cs Page_Load Response.Write(Request.Form["txtName"])
這兩種方式,地址欄並未發生重定向,因此這實際上還是利用了Form表單來實現值傳遞的。
3.Session:
//set Session["name"] = txtName.Value; //get string name = Session["name"].ToString();
4.Cookie:
//set HttpCookie cookie = new HttpCookie("MyCookie", aa); Response.Cookies.Add(cookie); //get HttpCookie myCookie = Request.Cookies["MyCookie"]; txt1.Value = myCookie.Value;
5.Cache
關於這個我不做敘述,詳細的用法可以看細說 ASP.NET Cache 及其高級用法
6.Application
//set Application["count"] = 12; //get int count= (int)Application["count"].;
7.ViewState
關於這個話題,我不做過多敘述,可以看下這篇文章Beginner's Guide To View State
Cross Page Posting (ASP.NET 2.0)
兩個概念CrossPageSource.aspx(來源網頁) CrossPageTarget.aspx(目標網頁)
1.獲取來源網頁的控件的值
//Default.aspx(來源網頁) <input type="text" id="txtName" runat="server" /> <asp:Button Text="test" runat="server" PostBackUrl="~/Default2.aspx" /> //Default2.aspx.cs(目標網頁) if (PreviousPage.IsCrossPagePostBack) { //獲取來源頁的控件的值 Response.Write(Request.Form["txtName"]);
//or Response.Write((PreviousPage.FindControl("txtName") as System.Web.UI.HtmlControls.HtmlInputText).Value); }
2.獲取源網頁屬性值
//Default.aspx(來源網頁) <input type="text" id="txtName" runat="server" /> <asp:Button Text="test" runat="server" PostBackUrl="~/Default2.aspx" /> //Default.aspx.cs 公共屬性
public string Name {
get {
return txtName.Value;
}
}
//Default2.aspx(目標網頁)
<%@ PreviousPageType VirtualPath="~/Default.aspx" %> //Default2.aspx.cs if (PreviousPage.IsCrossPagePostBack) { //獲取屬性的值
Response.Write(PreviousPage.Name); }
注:PreviousPage需要做非空判斷
Part 2 MVC傳值方式
在開始了解asp.net mvc各種傳值方式之前,我們先來看下面這張圖。它很形象的闡明了各個級別之間傳遞值的方式。
(來自互聯網)
從圖上不難看出asp.net mvc中獨有的傳值方式有ViewData、ViewBag、TempData。當然還有ViewModel和Model。當然細心的你可能發現這個圖並不完美。稍作改動如下:
ViewData\ViewBag
關於它們兩個我們先來看一組對照:
(圖片來自互聯網)
雖然ViewBag在asp.net mvc 3才出現,但它實質上它其實是一個包了一層Dynamic的ViewData(關於這個,可以看看ViewData和ViewBag的那些事,這里就不再細述),也就是對ViewData的封裝,這樣再看它們之間的差異時,我們就不難理解了。接下來看示例:
Action:
public ActionResult Index() { ViewData["Message1"] = "This Message is coming from ViewData"; ViewBag.Message = "This Message is coming from ViewBag"; return View(); }
View:
<div> @ViewData["Message1"] </div> <div> @ViewBag.Message </div>
結果:
上面講到VieBag實質上其實是一個包了一層Dynamic的ViewData,而我們對ViewBag的動態屬性進行賦值,值實際上是存到了ViewData中,動態屬性的名存成了ViewDataDictionary的鍵,動態屬性的值存成了ViewDataDictionary的值。為了論證這一點,我們將上面的代碼做下的改動,再看運行結果:(控制器)
-------------------------------------------------------------------------------------------------------------------------------
(運行結果)
果不其然,如同變量被重新賦值。由於實際上它們key同名了,而最終又是都是ViewDataDictionary的方式來存儲的,所以后來的值將原先的給覆蓋掉了。同樣的道理,即使后台不做改動,我們在前台通過@ViewData["Message"]取到的是ViewBag.Message的值:
(調試進程)
小結:ViewData、ViewBag主要是將數據從控制器級別傳遞到視圖級別
TempData
TempData是TempDataDictionary的字典類型。它不僅可以將數據從action傳遞到視圖,還可以傳遞到后續請求的action操作。在執行控制器的Execute()方法首先創建TempData對象(在Ruby On Rails中叫做Flash對象)。TempData可以用於保存下次請求必須的臨時數據(TempData和會話狀態差不多,不長期占用內存)。。接下來看示例:
(控制器)
-------------------------------------------------------------------------------------------------------------------------------
(視圖)
為了直接說明TempData可以將數據從一次請求傳遞到后續請求以及從控制器傳遞到視圖,我直接在TestTempData操作中創建TempData["BookData"],然后傳遞到Index操作中,然后在Index的視圖中展現數據。運行結果如下:
(運行結果)
-------------------------------------------------------------------------------------------------------------------------------
接下來,我們嘗試刷新頁面,很不幸的事情發生了:未將對象引用到對象的實例。調試發現TempData的值已經變為null:
(調試進程)
之所以會這樣這是由TempData的生命周期決定的:TempData只能保存數據到它的下一次請求。這其實是和TempData的存儲機制有關。關於TempData的實現機制可以看下下面這篇文章:淺談ASP.NET MVC中TempData的實現機制。當然asp.net mvc同樣為我們提供了TempDaa持續保存數據的實現方式:

public ActionResult Index() { Book book = TempData["BookData"] as Book; TempData.Keep("BookData"); //保存tempdate的值 return View(book); }
這也是基於TemData的實現機制,在下一次請求之前會移除TempData中任何沒有被更新的鍵值對。於是我們通過keep對響應的key進行更新。
ViewModel
public ActionResult Index() { Book book = TempData["BookData"] as Book; TempData.Keep("BookData"); //保存tempdate的值 return View(book); }
視圖:
<div> ID: @Model.ID<br /> BookName:@Model.BookName<br /> Author: @Model.Author<br /> ISBN: @Model.ISBN </div>
運行結果:
關於它們使用選擇的問題大家可以看下這篇文章:
Part 3 The end
其它的像Session、Application、Cookie、Cache因為是基於asp.net框架的,和webform中使用的方式是一樣的,這里就不做贅述。
注:由於個人技術有限,對某些概念的理解可能會存在偏差,如果你發現本文存在什么bug,請指正。謝謝!
完。