MVC&WebForm對照學習:傳值方式


剛從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&param2=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);
}
View Code

這也是基於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>

運行結果:

關於它們使用選擇的問題大家可以看下這篇文章:

When to use ViewBag, ViewData, or TempData in ASP.NET MVC 3 applications - See more at: http://rachelappel.com/when-to-use-viewbag-viewdata-or-tempdata-in-asp.net-mvc-3-applications#sthash.xQL1qFqG.dpuf

 

Part 3  The end

其它的像Session、Application、Cookie、Cache因為是基於asp.net框架的,和webform中使用的方式是一樣的,這里就不做贅述。

注:由於個人技術有限,對某些概念的理解可能會存在偏差,如果你發現本文存在什么bug,請指正。謝謝!

完。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM