ASP.NET保持使用者狀態的九種選擇(上)

來源:互聯網
上載者:User
asp.net 摘要:ASP.NET為保持使用者請求之間的資料提供了多種不同的途徑。你可以使用Application對象、cookie、hidden fields、Sessions或Cache對象,以及它們的大量的方法。決定什麼時候使用它們有時很困難。本文將介紹了上述的技術,給出了什麼時候使用它們的一些指導。儘管這些技術中有些在傳統ASP中已經存在,但是有了.NET架構組件後該在什麼時候使用它們發生了變化。為了在ASP.NET中保持資料,你需要調整從先前的ASP中處理狀態中學習到的知識。
  隨著Web時代的到來,在無狀態的HTTP世界中管理狀態成為Web開發人員的一個大問題。最近出現了幾種儲存和檢索資料的不同技術。本文我將解釋ASP.NET開發人員能怎樣通過頁面請求維護或傳遞狀態。

  在ASP.NET中,有幾種保持使用者請求間資料的途徑--實際上太多了,使沒有經驗的開發人員對在哪個特定的環境下使用哪個對象很困惑。為了回答這個問題,需要考慮下面三個條件:

   .誰需要資料?

   .資料需要保持多長時間?

   .資料集有多大?

  通過回答這些問題,你能決定哪個對象為保持ASP.NET應用程式請求間資料提供了最佳的解決方案。圖1列出了不同的狀態管理對象並描述了什麼時候使用它們。ASP.NET中添加了四個新的對象:Cache、Context、ViewState和Web.Config檔案。ASP.NET也支援傳統的ASP對象,包括Application、 Cookie、有隱藏欄位的 Form Post 、 QueryString和Sessions。注意這五個資料容器的正確使用方法發生了改變,因此有經驗的程式員在考慮這些熟悉的對象時也許需要學習一些知識。


保持方法誰需要資料保持多長時間資料量大小Application所有使用者整個應用程式生命期任意大小Cookie一個使用者可以很短,如果使用者不刪除也可以很長小的、簡單資料Form Post一個使用者到下一次請求(可以跨越多個請求重複使用)任意大小QueryString一個或一組使用者 到下一次請求(可以跨越多個請求重複使用)小的、簡單資料Sessions一個使用者使用者活動時一直保持+一段時間(一般20分鐘)可以是任何大小,但是因為使用者有單獨的Sessions 儲存,所有它應該最小。Cache 所有使用者或某些使用者根據需要可大可小、可簡單可複雜Context一個使用者 一個請求可以保持大對象,但是一般不這樣使用ViewState 一個使用者一個Web表單最小Config file所有使用者 知道設定檔被更新 可以保持大量資料,通常組織小的字串和XML結構

表1. ASP.NET中的資料容器物件

  Application

  讓我們通過回答上面的狀態問題判定條件來說明該對象。誰需要資料?所有的使用者需要訪問它。需要保持資料多長時間?永久保持,或在應用程式生存期中保持。資料多大?可以是任何大小--在任何給定的時刻只有資料的一個副本存在。

  在傳統ASP中,Application對象提供了一個儲存頻繁使用但很少改變的資料片的位置,例如菜單內容和參考資料。儘管在ASP.NET 中Application依然作為資料容器存在,但是有其它一些更適合以前儲存在傳統ASP應用程式的Application集合中的資料的對象。

  在傳統的ASP中,如果被儲存的資料在應用程式的生存期中根本不會改變(或很少改變,例如唯讀資料和大多數情況下是讀操作的資料),Application對象是理想的選擇。連接字串就是儲存在Application變數中的一個最普通的資料片,但是在ASP.NET中類似的配置資料最好儲存在Web.config檔案中。如果使用Application對象一個需要考慮的問題是任何寫操作要麼在Application_OnStart事件(global.asax)中,要麼在Application.Lock部分中完成。儘管使用Application.Lock來確保寫操作正確地執行是必要的,但是它序列化了對Application對象的請求,而這對於應用程式來說是個嚴重的效能瓶頸。圖2示範了怎樣使用Application對象,它包括一個Web表單和它的代碼檔案。

  Application.aspx


<form id="Application" method="post" runat="server">
<asp:validationsummary id="valSummary" Runat="server">
</asp:validationsummary>
<table>
<tr>
<td colSpan="3">Set Application Variable:</td>
</tr>
<tr>
<td>Name</td>
<td><asp:textbox id="txtName" Runat="server"></asp:textbox>
</td>
<td><asp:requiredfieldvalidator id="nameRequired"
runat="server" Display="Dynamic" ErrorMessage="Name is
required." ControlToValidate="txtName">*
</asp:requiredfieldvalidator></td>
</tr>
<tr>
<td>Value</td>
<td><asp:textbox id="txtValue" Runat="server">
</asp:textbox></td>
<td><asp:requiredfieldvalidator id="valueRequired"
Runat="server" Display="Dynamic" ErrorMessage="Value is
required." ControlToValidate="txtValue">*
</asp:requiredfieldvalidator></td>
</tr>
<tr>
<td colSpan="3"><asp:button id="btnSubmit" Runat="server"
Text="Update Value"></asp:button></td>
</tr>
</table>
<asp:Label ID="lblResult" Runat="server" />
</form>
Application.aspx.cs
private void btnSubmit_Click(object sender, System.EventArgs e)
{
if(IsValid)
{
Application.Lock();
Application[txtName.Text] = txtValue.Text;
Application.UnLock();
lblResult.Text = "The value of <b>" + txtName.Text +
"</b> in the Application object is <b>" +
Application[txtName.Text].ToString() + "</b>";
}

程式碼片段1.在ASP.NET中訪問Application對象

  它的輸出如下圖所示:

圖1. Application對象的內容

  注意圖3中Application對象的內容是追蹤輸出的顯示。追蹤是個偉大的調試工具,但是在某個點,被開啟的有追蹤的頁面可能出現在產品環境中。如果出現這種情況,你肯定不希望顯示敏感的資訊。這就是為什麼Application對象從來不是推薦的存放敏感資訊(例如連接字串)的位置的主要原因之一。

  Cookies

  當特定的使用者需要特定的資料片,並且需要把資料在某個可變的時段中保持的時候,cookie就非常方便。它的生命週期可能與瀏覽器表單的一樣短,也可以長達數月、數年。cookie可以小到只有幾個位元組的資料,因為它們在每個瀏覽器請求中傳遞,它們的內容需要儘可能的小。

  Cookie提供了一條靈活的、強大的維護使用者請求間資料的途徑,這就是為什麼Internet上大多數動態網站使用它們的原因。因為cookie可以儲存的資料量很受限制,最好只在cookie中儲存鍵欄位,其它的資料儲存在資料庫或其它的伺服器端資料容器中。但是由於不是所有的瀏覽器都支援cookie,並且它可以被使用者禁止或刪除,因此它們也不能用於儲存關鍵資料。你應該很好地處理使用者的cookie被刪除的情況。最後,cookie作為簡單的明文文本儲存在使用者的電腦中,因此在它裡面不能儲存敏感的、未加密的資料。

圖2.單值和多值cookie

  有種特殊的cookie可以儲存單個值或成對的名稱和數值的集合。圖4顯示了單個和多個值cookie的樣本,通過ASP.NET的內建追蹤特性輸出。這些值可以在ASP.NET頁面中使用Request.Cookies和Response.Cookies集合來維護,這在程式碼片段2中示範。

  Cookies.aspx.cs

//使用HttpCookie類是指cookie的值和/或子值
HttpCookie cookie;
if(Request.Cookies[txtName.Text] == null)
cookie = new HttpCookie(txtName.Text, txtValue.Text);
else
cookie = Request.Cookies[txtName.Text];
if(txtSubValueName.Text.Length > 0)
cookie.Values.Add(txtSubValueName.Text, txtSubValueValue.Text);
cookie.Expires = System.DateTime.Now.AddDays(1); // tomorrow
Response.AppendCookie(cookie);
//檢索cookie的值
if(!Request.Cookies[txtName.Text].HasKeys)
lblResult.Text = "The value of the <b>" + txtName.Text + "</b>
cookie is <b>" + Request.Cookies[txtName.Text].Value.ToString() +
"</b>";
else
{
lblResult.Text = "The value of the <b>" + txtName.Text + "</b>
cookie is <b>" + Request.Cookies[txtName.Text].Value.ToString() +
"</b>, with subvalues:<br>";
foreach(string key in Request.Cookies[txtName.Text].Values.Keys)
{
lblResult.Text += "[" + key + " = " +
Request.Cookies[txtName.Text].Values[key].ToString() + "]<br>";
}
}
刪除Cookie
// 把的值設定為空白並把終止時間設定為過去某個時刻
Response.Cookies[txtName.Text].Value = null;
Response.Cookies[txtName.Text].Expires =
System.DateTime.Now.AddMonths(-1); //上個月

程式碼片段2.Accessing 在ASP.NET中訪問Cookies

  Form Post / 隱藏的表單欄位

  特定的使用者需要表單的資料,並且它需要在單個請求到應用程式終止的任何階段都保持。這些資料事實上可以是任意大小的,它隨著每個form post在網路上向前和向後發送。

  在傳統的ASP中,這是在應用程式中暴露狀態的通常的途徑,特別是在多頁面表單應用程式中。但是在ASP.NET中這種技術不太適合了,因為只要你使用postback模型(也就是頁面發回給自己),Web控制項和ViewState自動處理了這些操作。ViewState是ASP.NET對這種技術的實現,我將在本文的後部分討論它。訪問通過POST發送的表單值是使用HttpRequest對象的表單集合完成的。在圖6中,一個ASP.NET版面設定了某個使用者的ID,在這以後它保持在一個隱藏的表單欄位中。後面的向任何頁面的請求保留這個值,直到頁面使用Submit按鈕連結到其它的使用者。

  Form1.aspx


<h1>Form 1</h1>
<form id="Application" method="post" runat="server">
<p>Your username:
<asp:Label ID="lblUsername" Runat="server" />
</p>
<asp:Panel Runat="server" ID="pnlSetValue">
<asp:validationsummary id="valSummary" Runat="server">
</asp:validationsummary>
<TABLE>
<TR>
<TD colSpan="3">Set Hidden Form Username Variable:</TD></TR>
<TR>
<TD>Username</TD>
<TD>
<asp:textbox id="txtName" Runat="server"></asp:textbox></TD>
<TD>
<asp:requiredfieldvalidator id="nameRequired" runat="server"
ControlToValidate="txtName" ErrorMessage="Name is required."
Display="Dynamic">*</asp:requiredfieldvalidator></TD></TR>
<TR>
<TD colSpan="3">
<asp:button id="btnSubmit" Runat="server" Text="Set Value">
</asp:button></TD></TR></TABLE>
</asp:Panel>
<asp:Label ID="lblResult" Runat="server" />
</form>
<form action="form2.aspx" method="post" name="form2" id="form2">
<input type="hidden" name="username" value="<%# username %>" >
<input type="submit" value="Go to Form2.aspx"
</form>
Form1.aspx.cs
private void Page_Load(object sender, System.EventArgs e)
{
if(!IsPostBack) // 新的請求或者來自form2.aspx的請求
{
// 檢查表單集合
if(Request.Form["username"] == null)
pnlSetValue.Visible = true;
else
{
//需要設定使用者名稱值
pnlSetValue.Visible = false;
username = Request.Form["username"].ToString();
lblUsername.Text = username;
//資料繫結到隱藏的表單欄位值
this.DataBind();
}
}
}

private void btnSubmit_Click(object sender, System.EventArgs e)
{
if(IsValid)
{
//隱藏表單來設定值
pnlSetValue.Visible = false;
username = txtName.Text;
lblResult.Text = "Username set to " + txtName.Text + ".";
lblUsername.Text = username;
this.DataBind();
}
}
Form2.aspx
<h1>Form 2</h1>
<form id="Application" method="post" runat="server">
<p>Your username: <asp:Label ID="lblUsername" Runat="server" /></p>
</form>
<form action="form1.aspx" method="post" id="form2" name="form2">
<input type="hidden" name="username" value="<%# username %>" >
<input type="submit" value="Go to Form1.aspx"
</form>
Form2.aspx.cs
private void Page_Load(object sender, System.EventArgs e)
{
if(Request.Form["username"] != null)
{
username = Request.Form["username"].ToString();
lblUsername.Text = username;
this.DataBind();
}
}
 

程式碼片段3.在ASP.NET中使用隱藏表單欄位

  在ASP.NET中一個頁面上只能存在一個伺服器端表單,並且該表單必須提交返回到自身(仍然可以使用用戶端表單,沒有限制)。隱藏表單欄位再也沒有用於在.NET架構組件上建立的應用程式間傳遞資料的主要原因之一是.NET架構組件控制項都可以使用ViewState自動維護自己的狀態。ViewState簡單地把使用隱藏表單欄位設定和檢索值所包含的工作封裝進一個使用簡單的集合對象中。

  QueryString

  QueryString對象中儲存的資料由單獨的使用者使用。它的生命週期可能只有一個請求那麼短,也可能有使用者使用應用程式的時間那麼長(如果構造正確的話)。這類資料一般小於1KB。QueryString中的資料在URL中傳遞,對於使用者來說是可見的,因此你能猜到,使用這種技術時,敏感的資料或可用於控制應用程式的資料需要加密。

  也就是說,QueryString是在ASP.NET Web表單間發送資訊的一條很好的途徑。例如,如果有一個含有產品列表的資料表格(DataGrid),並且在表格上有一個連結導向產品的細節頁面,使用QueryString就是理想的,可以把產品的ID包含在連結到產品細節頁面的QueryString中(例如productdetails.aspx?id=4)。使用QueryStrings的另一個好處是頁面的狀態包含在URL中。這意味著使用者可以把某個通過QueryStrings建立的表單放入他的收藏夾中。當它們作為收藏返回到頁面時,將與作收藏的時候一樣。很明顯這隻在頁面不依賴QueryString外的所有狀態和不作任何改變的時候有作用。

  敏感性資料,以及任何不希望使用者操作的變數應該避免出現在此處(除非加密使使用者不能閱讀)。並且URL中不合法的字元必須使用Server.UrlEncode編碼,如圖7所示。當處理單個ASP.NET頁面時,對維護狀態來說ViewState是比QueryString好的選擇。對於長期的資料存放區,Cookie、Sessions或Cache都比QueryStrings更加適於作為資料容器。

  Querystring.aspx


<form id="Querystring" method="post" runat="server">
<asp:validationsummary id="valSummary" Runat="server">
</asp:validationsummary>
<table>
<tr>
<td colSpan="3">Set Querystring Variable:</td>
</tr>
<tr>
<td>Name</td>
<td><asp:textbox id="txtName" Runat="server"></asp:textbox>
</td>
<td><asp:requiredfieldvalidator id="nameRequired"
runat="server" Display="Dynamic" ErrorMessage="Name is
required." ControlToValidate="txtName">*
</asp:requiredfieldvalidator></td>
</tr>
<tr>
<td>Value</td>
<td><asp:textbox id="txtValue" Runat="server">
</asp:textbox></td>
<td><asp:requiredfieldvalidator id="valueRequired"
Runat="server" Display="Dynamic" ErrorMessage="Value is
required." ControlToValidate="txtValue">*
</asp:requiredfieldvalidator></td>
</tr>
<tr>
<td colSpan="3"><asp:button id="btnSubmit" Runat="server"
Text="Update Value"></asp:button></td>
</tr>
</table>
<asp:Label ID="lblResult" Runat="server" />
<a href="querystring.aspx?x=1">Set querystring x equal to 1</a>
</form>
Querystring.aspx.cs
private void Page_Load(object sender, System.EventArgs e)
{
// 檢索cookie的值
if(Request.QueryString.HasKeys())
{
lblResult.Text = "The values of the <b>" + txtName.Text +
"</b> querystring parameter are:<br>";
foreach(string key in Request.QueryString.Keys)
{
lblResult.Text += "[" + key + " = " +
Request.QueryString[key].ToString() + "]<br>";
}
}
}

private void btnSubmit_Click(object sender, System.EventArgs e)
{
if(IsValid)
{
string url = "querystring.aspx?";
foreach(string key in Request.QueryString.Keys)
{
url += key + "=" + Request.QueryString[key].ToString() + "&";
}
Response.Redirect(url + txtName.Text + "=" +
Server.UrlEncode(txtValue.Text));
}
}
 

程式碼片段4.在ASP.NET中使用QueryStrings傳遞資料


  Sessions

  Sessions資料對於特定的使用者是特定的。它的生存期是使用者持續請求的時間加上後來一段時間(一般是20分鐘)。Sessions可以保持或大或小的資料量,但是如果應用程式用於成百上千的使用者,那麼總共的儲存應該保持最小。

  不幸的是在傳統的ASP中Sessions對象的名聲很不好,因為它把應用程式約束到特定的電腦上,阻礙了使用者分組和Web範圍的延展性。在ASP.NET中幾乎沒有這些問題,因為改變Sessions儲存的位置很簡單。在預設情況下(效能最好的情況),Sessions資料仍然儲存在本地Web伺服器的記憶體中,但是ASP.NET支援使用外部狀態伺服器或資料庫管理Sessions資料。

  使用Sessions對象很簡單,並且它的文法與傳統ASP相同。但是Sessions對象是儲存使用者資料的方法中效率很低的一種,因為即使使用者停止使用應用程式後它仍然保持在記憶體中一段時間。這對於非常繁忙的網站的延展性有嚴重的影響。其它的選擇允許對釋放記憶體的更多的控制,例如Cache對象也許更適合大量的大資料值。並且在預設情況下ASP.NET Sessionss依賴於cookie,因此如果使用者禁止或不支援cookie,Sessionss就不能工作,但是可以配置Sessionss支援cookie無關。對於小的資料量,Sessionss對象是儲存只需要在使用者目前的交談中保持的特定資料的極好位置。下面的例子示範了怎樣設定和從Sessionss對象中檢索值:


private void btnSubmit_Click(object sender, System.EventArgs e)
{
 if(IsValid)
 {
  // 設定Sessions值
  Sessions[txtName.Text] = txtValue.Text;

  //讀取和顯示剛才的設定
  lblResult.Text = "The value of <b>" + txtName.Text + "</b> in the Sessions object is <b>" + Sessions[txtName.Text].ToString() + "</b>";
 }
}
 

  該Web表單與Application對象中使用的幾乎相同,當允許頁面追蹤時Sessions集合的內容也是可見的。
你需要記住的是即使沒有使用,Sessionss也會有應用程式開銷。把Sessionss狀態設定為唯讀也可以最佳化只需要讀而不需要寫資料的頁面。可以使用下面兩種途徑之一來配置Sessionss:


<%@ Page EnableSessionsstate="false" %>
<%@ Page EnableSessionsstate="readonly" %>

  ASP.NET Sessionss可以在Web.config或Machine.config中的Sessionsstate元素中配置。下面是在 Web.config中的設定的例子:


<Sessionsstate timeout="10" cookieless="false" mode="Inproc" />




聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.