最近同事在Client-side修改asp.net web form控制項的內容,但postback到Server-Side後抓不到值,同事發生問題的控制項是Label,但我們常使用的TextBox控制項則可以,另外根據MSDN上的說明,使用 Label 控制項可以用來顯示在頁面上設定位置的文字,好,馬上實驗Http Request內容是否有帶postdata?
建立環境:
1.新增ViewStateAndPostData.aspx
分別建立三個會在前端修改值的控制項,依序為Textbox、HiddenField及Label,同時新增兩個按鈕,分別是client端事件按鈕及postback回server side的按鈕。
在client事件中會分別將三個控制項的值依序改為iPhone8、S8 Edge及xz premium。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ViewStateAndPostData.aspx.cs" Inherits="WebApplication1.ViewStateAndPostData" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<script>
function changeText() {
document.getElementById("txtInPut").value = "iPhone8";
document.getElementById("hdfInPut").value = "S8 Edge";
document.getElementById("lblInPut").innerHTML = "xz premium";
};
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="txtInPut" runat="server"></asp:TextBox>
<asp:HiddenField ID="hdfInPut" runat="server"></asp:HiddenField>
<asp:Label ID="lblInPut" runat="server"></asp:Label>
<button type="button" onclick="changeText()">手機型號</button>
<asp:Button ID="btnPost" Text="PostBack的按鈕" runat="server" OnClick="btnPost_Click" />
</div>
</form>
</body>
</html>
2.按F7切換到code behind(ViewStateAndPostData.aspx.cs)
a.若是第一次載入頁面,則將三個控制項依序帶入apple、samsung及sony。
b.依序在Page_Init、Page_Load、post_back event及Page_PreRender觀察三個控制項的值
protected void Page_Init(object sender, EventArgs e)
{
Debug.WriteLine($"Page_Init Text = {this.txtInPut.Text}");
Debug.WriteLine($"Page_Init HidenField= {this.hdfInPut.Value}");
Debug.WriteLine($"Page_Init Label = {this.lblInPut.Text}");
}
protected void Page_Load(object sender, EventArgs e)
{
Debug.WriteLine($"Page_Load Text = {this.txtInPut.Text}");
Debug.WriteLine($"Page_Load HidenField= {this.hdfInPut.Value}");
Debug.WriteLine($"Page_Load Label = {this.lblInPut.Text}");
if (!Page.IsPostBack)
{
this.txtInPut.Text = "apple";
this.hdfInPut.Value = "samsung";
this.lblInPut.Text = "sony";
}
}
protected void btnPost_Click(object sender, EventArgs e)
{
Debug.WriteLine($"btnPost_Click Text = {this.txtInPut.Text}");
Debug.WriteLine($"btnPost_Click HidenField= {this.hdfInPut.Value}");
Debug.WriteLine($"btnPost_Click Label = {this.lblInPut.Text}");
}
protected void Page_PreRender(object sender, EventArgs e)
{
Debug.WriteLine($"Page_PreRender Text = {this.txtInPut.Text}");
Debug.WriteLine($"Page_PreRender HidenField= {this.hdfInPut.Value}");
Debug.WriteLine($"Page_PreRender Label = {this.lblInPut.Text}");
}
實驗
1.第一次執行畫面:
在Page Render之前,判斷使用者第一次載入網頁(非Page.IsPostBack)時的預設值apple、samsung及sony都有在。
Ctrl + Alt + O 看輸出
2.按下F12 開發人員工具,網路>啟動錄製
3.點選手機型號(Client-Side Button)
A.從肉眼觀察畫面,此時textbox中的apple被javascript方法changeText()換成iphone8了、label也被置換成xz premium。
B.打開網頁原始檔(Ctrl + U) 觀察raw HTML
HTML原始檔中,只有Label(span標籤)沒有改變,還是維持著Server-Side初始給的sony!
C.從F12開發人員工具中的DOM總管:
經過client-side script處理後的網頁,三個手機型號的值都帶出來了!
4. 點選postback的按鈕(Server-Side Button),這時可以發現F12 開發人員工具有錄到request。
Request Header
Request Content
Postdata只有iphone8(textbox)及s8 edge(hidenfield),Label果然沒有帶postdata(變更後的值xz premium)
5.Decode viewstate: 好在至少還有修改前的狀態sony。
回到Label目的: 顯示在頁面上設定位置的文字!
沒有postdata好像也合情合理的。
6.從server-side的偵錯輸出(Ctrl + ALt + O)也反應出同事的問題,textbox、hidenfield都依序載入viewstate及postdata,但label只能載入viewstate,值還是維持sony。
ASP.NET載入Viewstate及Postdata順序
https://msdn.microsoft.com/en-us/library/ms972976.aspx
補充:
順便筆記同事另一個viewstate問題: 這個案例中,為什麼viewstate只有Label的?
因為Textbox和HiddenField都會實作IPostDataHandler,背後會自己處理,這也是停用這些有實作IPostDataHandler控制項viewstate不太有幫助的原因。
小結:
- 解決問題的方式就是用hidenfield來藏client-side的值,postback到server-side再來接。
- 每次幫新學ASP.NET的同事Debug都有新收穫。
參考:
losing Label text on postback help
Understanding ASP.NET View State