頁面間傳遞數據的幾種方法
在頁面間傳遞數據時,我們有以下幾種選擇:
1、Query String
??? 一個很常見的方法,Query String是URL中問號之后的那一部分。其優點在于它是輕量級的,不會給服務器帶來任何負擔。而它也有幾個缺點:傳遞的信息僅限于簡單的字符串,而且必須是合法的URL字符;信息是對用戶是可見的,因而存在安全性問題;用戶可能會嘗試手動修改查詢字符串,這可能是程序未預料到或不能防范的;很多瀏覽器對URL的長度都有所限制(通常為1KB到2KB)。
2、Cookie
??? Cookie是創建在客戶端硬盤上(或者,如果它們是臨時的,則在內存中)的小文件。其優點在于使用時不易被用戶察覺,可被程序中每個頁面使用,并且可將數據長期保存。但它也有一些與Query String 相同的缺點:僅限于簡單的字符串信息;一旦用戶找到了相應的文件,它們也是易于訪問和閱讀的。所以Cookie最好不要用于保存復雜的或私密的信息。
3、Session
??? 可以在源頁面中將數據保存在Session中,然后在目標頁面中讀取這些數據。注意:將大量的信息存儲在Session中會嚴重影響服務器的性能。
4、Server.Transfer
??? 要進行服務器端的重定向,可以使用Server.Transfer。因為在服務器端執行,Server.Transfer方法不需要請求另一頁面。使用HttpContext,我們可以在目標頁面中訪問源頁面中的數據。其缺點是,瀏覽器并不了解返回給它的是另外一個頁面,它在地址欄中會顯示第一個頁面的URL,這會讓用戶陷入混亂,在他們使用書簽的時候也會產生麻煩。所以不推薦該方法。
5、其它
??? 還可以使用緩存(Cache)來存儲數據,可在程序的任意處訪問緩存。建議僅對那些修改不太頻繁但經常使用的數據使用緩存。 另外在某些特定情況下還可以使用Application變量,如統計頁面的點擊數等。
使用Cross-Page Postback
ASP.NET 2.0中引入了一個新的方法:跨頁面提交,即postback觸發在另一個頁面。這種技術聽起來很是簡單,但卻存在隱患。一不小心,就會導致你創建的頁面緊密耦合,難以維護和調試。
支持跨頁面提交的機制是一個名為PostBackUrl的屬性,該屬性由IButtonControl接口定義,實現這個接口的按鈕控件包括ImageButton,LinkButton,Button。將PostBackUrl屬性值設置為另一個web窗體的名稱(即URL),當用戶點擊按鈕時,頁面將被提交到新的URL。
看下面這個示例,該示例包括源頁面CrossPage1.aspx和目標頁面CrossPage2.aspx:?
CrossPage1.aspx
<head?runat="server">
????<title>Source?Page</title>
</head>
<body>
????<form?id="form1"?runat="server">
????<div>
????????FirstName:?<asp:TextBox?runat="server"?ID="txtFirstName"></asp:TextBox>
????????<br?/>
????????LastName: <asp:TextBox?runat="server"?ID="txtLastName"></asp:TextBox>?
????????<br?/>
????????<asp:Button?runat="server"?ID="cmdSubmit"?PostBackUrl="~/CrossPage2.aspx"?Text="Cross-Page?Postback"?/>
????</div>
????</form>
</body>
</html>
CrossPage1.aspx不包含任何代碼,效果如下:
現在點擊按鈕,該頁面就被提交到CrossPage2.aspx了。此時CrossPage2.aspx頁面可以使用Page.PreviousPage屬性與CrossPage1.aspx進行交互了,下面這個事件處理函數演示了如何獲取源頁面的標題并顯示它:
{
????lblInfo.Text?=?"You?came?from?a?page?titled?"?+?PreviousPage.Header.Title;
}
注意:該方法在訪問PreviousPage對象前先對其作了null檢查,如果結果為false,表明沒有跨頁面提交發生,也就是說,CrossPage2.aspx是被直接請求的,或者由其自身提交,此時PreviousPage對象不可用。
從源頁面中獲取更多數據
上面那個示例作了一個有趣的嘗試,但僅僅如此,我們還是不能傳遞任何有用的信息。?
要獲取源頁面中控件的值,可以使用FindControl方法:
{
????lblInfo.Text?=?"You?came?from?a?page?title?"?+?PreviousPage.Header.Title;
????string?firstName?=?(PreviousPage.FindControl("txtFirstName")?as?TextBox).Text;
????string?lastName?=?(PreviousPage.FindControl("txtLastName")?as?TextBox).Text;
????lblInfo.Text?+=?"<br?/>";
????lblInfo.Text?+=?"your?full?name:?"?+?firstName?+?"?"?+?lastName;
}
要獲得更多信息,我們需要將PreviousPage引用轉換為適當的頁面類(本示例中是CrossPage1類):
{
????CrossPage1?prevPage?=?PreviousPage?as?CrossPage1;
????if?(prevPage?!=?null)
????{
????????//?此時可以訪問源頁面的公共屬性
????}
}
另外,除了在代碼中進行類型轉換,還可以在.aspx頁面中添加PreviousPageType指示字:
<%@ PreviousPageType VirtualPath="~/CrossPage1.aspx" %>
此時,PreviousPage屬性會自動使用CrossPage1類型,編輯器中的智能提示也可以使用了。但是這種方法相當脆弱,因為你只能使用一個頁面類!因此,出于靈活性考慮,使用類型轉換的方法會更好。
好了,不管怎樣,現在已經將PreviousPage對象轉換為合適的頁面類型了,但是你還是不能直接訪問它包含的控件對象。這是因為這些控件都被聲明為保護類型(protected),此時的解決方案是使用屬性。
比如,如果希望公開源頁面上兩個文本框控件的值,可以添加屬性來封裝控件對象,如在CrossPage1類中添加屬性:
{
????get?{?return?txtFirstName;?}
}
public?TextBox?LastNameTextBox
{
????get?{?return?txtLastName;?}
}
但是,這通常不是最好的方法。其問題在于它公開了太多的細節,目標頁面可以讀取文本框控件的所有內容了。如果過段時間需要修改源頁面,決定使用不同的輸入控件,維護這些屬性就相當困難了,因為你不得不修改兩個頁面的代碼。
更好的方法是定義更具體的屬性,它們應當僅僅提供你需要的東西。比如,你可以考慮添加一個FullName屬性,該屬性讀取兩個文本框的值:
{
????get?{?return?this.txtFirstName.Text?+?"?"?+?this.txtLastName.Text;?}
}
這樣做,兩個頁面的關系就變得清晰、簡單并易于維護了。如果你決定在CrossPage1中使用新的輸入控件,只要修改CrossPage1頁面就好了。CrossPage2中的代碼也相應地修改如下:
{
????lblInfo.Text?=?"You?came?from?a?page?titled?"?+?PreviousPage.Header.Title?+?"<br?/>";
????CrossPage1?prevPage?=?PreviousPage?as?CrossPage1;
????if?(prevPage?!=?null)
????{
????????lblInfo.Text?+=?"You?typed?in?this:?"?+?prevPage.FullName;
????}
}
?
下面是CrossPage2的最終結果:
跨頁面提交確實非常有用,但它們也會使頁面變得復雜。如果你允許多個源頁面提交到同一目標頁面,你就得編寫代碼邏輯以判斷頁面來自何處,然后作出相應處理。要避免這種煩惱,簡單的方法就是只在兩個特定的頁面間使用它。
??????????????????????????????????????????????????????????????????????????????????????????????????By Anders Cui
參考:
? Beginning.ASP.NET.2.0.in.C.Sharp.2005.From.Novice.to.Professional by Matthew MacDonald