日期: 2023.10.17 星期四
狀態管理式網頁好重要的環節,Client 端發出請求給伺服器後就會斷線,執行過程中所有生成的資料都不會保存。
問題: 若有些資料需儲存起來怎麼辦
ViewStatge 技術乃指 Client 發出請求給伺服器端時,伺服器端會利用 ViewState 技術先儲存特定資料在 postback 後的 html 頁面上,等下一次做 PostBack 時(即回傳結果於 Client 時),再取出該資料作應用。
- 產生一
Web 表單,名稱WebForm1 -
UI 介面:
Label1Button(按下顯示 PostBack 幾次於 Label1.Text 上) 只有按下第一次不是 PostBack, 其他次都是 PostBack
-
Button1事件Button1_Click(){ int counter; //不存在該物件 ViewState["counter"] 時 if(ViewState["counter"] == null){ counter = 1; }else{ counter = (int) ViewState["counter"] + 1; } //做完之後重新設定(刷新) ViewStage 的值 ViewState["counter"] = counter; Label1.Text = counter.ToString(); }ViewState執行表單WebForm1.aspx將值提交給伺服器端後就會消失,但是它在提交時,表單內有一隱藏欄位會記錄該值,檢視原始碼,顯示的該內容是上一次執行完WebForm1.aspx回傳的html結果畫面:server回傳結果時會自動加一個隱藏欄位填加該加一後的count值放在屬性value="xxx"裡面其中<form> : <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="64bit 的編碼,乃為 viewstate 的資料" : <input type=submit> </form>value值紀錄 label1 屬性與 Button1 屬性 與 coumter 的值,當按下 Button1 就會提交(submit)該 value,提交到伺服器端,伺服器會將該 __VIEWSTATE 的值解碼得到該相對值。
練習
寫一 web form,上面有一 TextBox, TextBox 上可以輸入任何文字,有 3 個按鈕,第一個按鈕是 submit,按下去會把 TextBox 輸入的內容顯示在 Label1 上,另一個按鈕 "儲存" 當按下該按鈕會儲存該 TextBox1 輸入的值,
另一個按鈕 "還原",當按下時會把之前儲存起來的值顯示在 TextBox 上。 (不管你按了多少次 Submit, 當按下 "還原" 按鈕就會還原該儲存過後的值於 TextBox1 上)
解答
給一 WebForm2.aspx 表單後, 新增 TextBox1,Button *3 ("Submit"、"Save"、"Resume"),Label1 (顯示 Submit 後的結果)
-
雙擊
Submit按鈕,產生Button1_Click(){ Label1.Text = TextBox1.Text; } -
雙擊
Save按鈕,產生Button2_Click(){ ViewState["content"] = TextBox1.Text; } -
雙擊
Resume按鈕,產生Button3_Click(){ //是否無值,即未曾按下 "Save" 按鈕 if(ViewState["content"] == null){ Label1.Text = "No saved data"; }else{ TextBox1.Text = ViewState["content"].ToString(); } } - 測試執行
WebForm2.aspx - 到目前都是單一網頁執行,接下來是跨網頁(網頁間溝通與傳遞資料):
網頁間如何做到跳轉
對 http 協定來說,client 端會送一 Request 物件給 Server, 要求 Server 作一些事情, Server 端處理完事件後會下載一 Response 物件給 Client 端
你的瀏覽器根據收到的 Response 物件,解析後刷新頁面
-
UI: 如下,按下
WebFomr1上的WebForm2按鈕會執行表單 WebForm2.aspxWebForm1
WebForm2
Label1Button1(名稱:Button): 按一次Label1+1,Button2(名稱:WebForm2): 按一下跳轉WebForm2 -
方法 1:
Response.Redirect(url), 雙擊WebForm1.aspx表單上的Button2按鈕Button2_Click(){ //Client 端要要求 Server 端去執行 WebForm2 //Response 物件要求 Browser 收到該 Response 物件時,馬上在下一個 URL 指令給伺服器 Response.Redirect("WebForm2.aspx"); } -
方法 2:
Server.Transfer()
在WebForm1上多加一個按鈕WebForm2+
雙擊 WebForm1.aspx 表單上的WebForm2+按鈕Button3_Click(){ //Server 物件的 `Transfer()` 方法,告訴 Server 要轉移到哪一個地方 Server.Transfer("WebForm2.aspx"); }方法 1 與方法 2 都是跳轉頁面的功能,但是調用 Server.Transfer() 這方法執行後,其網址仍停留於原位置。
http://localhost:55212/WebForm1.aspx, 而不是http://localhost:55212/WebForm2.aspx
原因:
執行 Response.Redirect(url) 時,即執行WebForm2按鈕時,你的瀏覽器會至少送出兩次 Request 物件。
WebForm1 頁面上,第一次 Request 時機是當按下按鈕WebForm2要跳轉頁面的需求,執行完畢後產生 Response 物件,Server 端會下載 Response 物件給使用者端後,當 Client 端收到 Response 物件
看到 Response 物件有一 Redirect() 方法,即是要求告訴瀏覽器馬上在連接到 Server 端去執行 WebForm2.aspx 頁面(第二次 Request),所以網址會變成http://localhost:55212/WebForm2.aspx若 Server 的 Transfer() 方法,當執行 WebForm1,按下是按鈕
Button3_Click()做了 Server 的 Transfer() 方法後,會結束 WebForm1 後面的所有程序 ,不在往後執行,直接告訴 Server 去執行 WebFomr2,執行後得到結果下載下來給使用者看,所以看到的是 WebForm2 執行的內容結果,但這時網址不會有任何變化,仍維持在http://localhost:55212/WebForm1.aspx, 所以只有一次的 Request
頁面資料做轉移
方法 1. Cookie: Client 端上小檔案
-
UI表單
WebForm1
WebForm2
WebForm3
WebForm4 -
WebForm3表單上TextBox1輸入資料
Button11將資料傳到WebForm4 -
WebForm4表單上
Label1顯示接收來至WebForm3的textBox1的資料 -
雙擊
WebForm3.Button1_ClickButton1_Click(){ //資料存在 Client 端,不能用 ViewState 因是使用於不同頁面 HttpCookie cc = new HttpCookie("hello"); //建構式參數需指定 Cookie 名稱 //單一值時 cc.Value = TextBox1.Text; //多值時用 Collection 物件。 Values //cc.Values.Add("name", TextBox1.Text); //cc["name"] = TextBox1.Text; //有效期間, 1 年後失效 cc.Expires=DateTime.Now.addYears(1); //如何下載給使用者,透過 Response 物件的屬性 Cookies 將多個 Cookie 資料封裝起來 Response.Cookies.Add(cc) //下載 Response 物件後執行 WebForm4.aspx Response.Redirect("WebForm4.aspx"); } -
WebForm4.aspxPage_Load(){ //透過 Request 取的上傳的 Cookie HttpCookie cc = Request.Cookies["name"]; if (cc != null) Label1.Text = cc["name"]; else Label1.Text = "No cookies"; } }
方法 2. QueryString() 方法,即 http 的 GET
-
WebForm3.aspx.cs“`C#
protected void Button1_Click(object sender, EventArgs e){
string r = TextBox1.Text;
// 代表 QueryString 有有變數 name 與 age
// 其中 & 是 url 中特殊符號
// 使用此方法會將資料顯示網址上,不安全
Response.Redirect("WebForm4.aspx?name=" + r + "&age=13");
//所以改用 Server.Transfer() 就不會將資料顯示在網址上
//Serve.Transfer("WebForm4.aspx?name=" + r);
} -
WebForm4.aspx.cs“`C#
protected void Page_Load(object sender, EventArgs e){
//接收 URL 上傳遞過來的值
Label1.Text = Request.QueryString["name"];
} -
測試:
- 執行
WebForm3.aspx.c,輸入框輸入abc,按下按鈕,會轉向WebForm4.aspx.cs的網頁,網址:localhost:55212/WebFrom4.aspx?name=abc。 畫面結果輸出正常
問題::
因需要看網址的變化內容,
WebForm3.aspx.cs的Button1_Click上使用Response.Redirect("WebForm4.aspx?name=" + r + "&age=13");方法執行
WebForm3.aspx.c,輸入框輸入abc&123,按下按鈕,會轉向WebForm4.aspx.cs的網頁,畫面結果輸出只有字串abc,不正常,但網址顯示的是正確的訊息localhost:55212/WebFrom4.aspx?name=123。原因:
在HTTP協定中,很多符號有特殊意義,例如:&符號在url代表是參數跟參數的分隔。例如: 在
WebForm3.aspx.c的Button1_Click上寫Response.Redirect("WebForm4.aspx?name=" + r + "&age=13");代表在Query String內有兩變數(name與age),其中&符號是url的特殊符號,1 表示空白,所以後面的資料age=13會被切掉,但網路上有需要傳遞這些特殊符號資料,解決辦法針對使用者輸入資料做編碼(會將特殊符號轉成一個百分比符號加上二位數字),所以改寫如下:解決:
WebForm3.aspx.csprotected void Button1_Click(object sender, EventArgs e){ string r = TextBox1.Text; Response.Redirect("WebForm4.aspx?name=" + Server.UrlEncoder(r) );WebForm4.aspx.cs“`C#
protected void Page_Load(object sender, EventArgs e){
//接收 URL 上傳遞過來的值
//Label1.Text = Server.UrlDecorder(Request.QueryString["name"]);
//但不寫也可以自動做解碼
Label1.Text = Request.QueryString["name"];
}**測試**: 修改後執行 `WebForm3.aspx.c`,輸入框輸入 `abc&123`,按下 `按鈕`,會轉向 `WebForm4.aspx.cs` 的網頁,畫面結果輸出正常而且 `URL` 也顯示的是正確的訊息 `localhost:55212/WebFrom4.aspx?name=123`。 - 執行
-
練習
在網頁中輸入兩數字,這兩數字相乘後結果傳送到另一網頁做顯示。- 作法 1: 在第一網頁做出相乘結果在送至第二頁面。
- 作法 2: 在第一網頁先送出兩數資料後,在到第二網頁相乘,然後結果秀在第二頁面。
解答:
- 產生兩
WebForm表單(WebForm5.aspx.cs、WebForm6.spx.cs)WebForm5.aspx.cs,UI為1 標籤WebForm6.aspx.cs,UI為2 輸入文字框與1 按鈕
-
雙擊
WebForm6.aspx.cs的按鈕protected void Button1_Click(object sender, EventArgs e){ string n1 = TextBox1.Text; string n2 = TextBox2.Text; Response.Redirect("WebForm5.aspx?n1=" + n1 + "&n2=" + n2 );網際網路上所傳遞的資料都是字串
-
回到
WebForm5.aspx.cs“`C#
protected void Page_Load(object sender, EventArgs e){
int n1 = Int32.Parse(Request.QueryString["n1"]);
int n2 = Int32.Parse(Request.QueryString["n2"]);
Label1.Tet = (n1*n2).ToString();
}
留言