1. 程式人生 > >.NET框架學習:淺談ASP.NET的Postback

.NET框架學習:淺談ASP.NET的Postback

說道ASP.NET的Postback,就得說Web Page的生命週期,但是Web Page的生命週期卻不是三言兩語就能夠說得清楚的,所以在這裡單純站的程式設計的角度,撇開Web Page 的生命週期淺談Postback。

我們知道,無論是ASP.NET1.x,2.0,甚至是以後的版本,ASP.NET最終Render到Client端通過瀏覽器瀏覽的都是一樣:一個單純的HTML。Client通過Submit Form的方式將填入Form的資料提交給Server進行處理。我們現在來看看ASP.NET整個Postback程式處理的過程。

首先我們通過一個Sample來看ASP.NET如何處理一個通過Click一個Button引起的Postback。下面是Web Page的HTML:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    
<title
>Test Page</title>
</head>
<body>
    
<form id="form1" runat="server">
        
<div>
            
<asp:Label runat="server" ID="LabelMessage" ForeColor="red"></asp:Label>
        
</div>
        
<div>
            
<asp:Button runat="server" ID="Button1" Text
="Button1" OnClick="Button1_Click" OnCommand="Button_Command"     CommandArgument="Button1"/>
            
<asp:Button runat="server" ID="Button2" Text="Button2" OnClick="Button2_Click" OnCommand="Button_Command"    CommandArgument="Button2" UseSubmitBehavior="false"/>
            
<asp:Button runat="server" ID="Button3" Text="Button3" OnClick="Button3_Click" OnCommand="Button_Command"    CommandArgument="Button3" UseSubmitBehavior="false"/>
        
</div>
    
</form>
</body>
</html>

很簡單,定義了3個Button,分別註冊了他們的兩個Event:Click和Command。3個Button的Command Event Hander是一樣的:Button_Command,通過指定的CommandArgument來讓Event Handler判斷到底是哪個Button觸發了Command  Event。

下面是Code Behind:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{  

    
protectedvoid Page_Load(object sender, EventArgs e)
    
{
       
    }

    
protectedvoid Button1_Click(object sender, EventArgs e)
    
{
        
string message =string.Format("The {0} event of {1} is fired""Click""Button1");
        
this.LabelMessage.Text = message;
    }

    
protectedvoid Button2_Click(object sender, EventArgs e)
    
{
        
string message =string.Format("The {0} event of {1} is fired""Click""Button2");
        
this.LabelMessage.Text = message;
    }

    
protectedvoid Button3_Click(object sender, EventArgs e)
    
{
        
string message =string.Format("The {0} event of {1} is fired""Click""Button3");
        
this.LabelMessage.Text = message;
    }


    
protectedvoid Button_Command(object sender, CommandEventArgs e)
    
{
        
string message =string.Format("The {0} event of {1} is fired""Command", e.CommandArgument);
        
this.LabelMessage.Text +=""+ message;
    }

}

我們來執行這個Page,並Click某個按鈕(比如Button2):


我們通過最上方的Message可以看出,Button2的Click Event和Command先後觸發。

這篇Blog的主旨就是從方法呼叫的角度講述整個程式執行的過程:從HTML 被Render到Client端,到使用者Click某個按鈕,輸入被Postback到Server端,並觸發兩個Event,執行Event Handler打印出相關的Message。

首先我們來看看ASP.NET設計的Page Render到Client端的HTML是什麼樣子:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    
<head>
        
<title>
            Test Page
        
</title>
    
</head>
    
<body>
        
<form name="form1" method="post" action="Default.aspx" id="form1">
            
<div>
                
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value=""/>
                
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value=""/>
                
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTA0NDQ2OTE5OWRk281L4eAk7iZT10hzg+BeOyoUWBQ="/>
            
</div>

<script type="text/javascript">
                
<!--
var theForm = document.forms['form1'];
if (!theForm) {
    theForm 
= document.form1;
}

function __doPostBack(eventTarget, eventArgument) {
    
if (!theForm.onsubmit || (theForm.onsubmit() !=false)) {
        theForm.__EVENTTARGET.value 
= eventTarget;
        theForm.__EVENTARGUMENT.value 
= eventArgument;
        theForm.submit();
    }

}

// -->
</script>

<div>
<span id="LabelMessage" style="color:Red;"></span>
</div>
<div>
    
<input type="submit" name="Button1" value="Button1" id="Button1"/>
    
<input type="button" name="Button2" value="Button2" onclick="javascript:__doPostBack('Button2','')" id="Button2"/>
    
<input type="button" name="Button3" value="Button3" onclick="javascript:__doPostBack('Button3','')" id="Button3"/>
</div>
</form>
</body>
</html>

上面的HTMLBody部分大體包括3個部分:

1.   定義了3個hidden field:

<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value=""/>                
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value=""/>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTA0NDQ2OTE5OWRk281L4eAk7iZT10hzg+BeOyoUWBQ="/>

從他們的命名可以看出他們分別代表的意思:__EVENTTARGET代表觸發Event的Control的Unique name;__EVENTARGUMENT代表為Event Handler定義的額外的引數;__VIEWSTATE:代表的是Viewstate。

2.   一段script:

<script type="text/javascript">
                
<!--
var theForm = document.forms['form1'];
if (!theForm) {
    theForm 
= document.form1;
}

function __doPostBack(eventTarget, eventArgument) {
    
if (!theForm.onsubmit || (theForm.onsubmit() !=false)) {
        theForm.__EVENTTARGET.value 
= eventTarget;
        theForm.__EVENTARGUMENT.value 
= eventArgument;
        theForm.submit();
    }

}

// -->
</script>
定義了一個__doPostBack function完成Postback的操作,該function只有區區3行程式碼,前兩行通過引數對上面定義的兩個hidden field賦值,然後向Server端提交表單。

3.   一段HTML對應通過ASP.NET定義的Web Control。 

<div>
<span id="LabelMessage" style="color:Red;"></span>
</div>
<div>
    
<input type="submit" name="Button1" value="Button1" id="Button1"/>
    
<input type="button" name="Button2" value="Button2" onclick="javascript:__doPostBack('Button2','')" id="Button2"/>
    
<input type="button" name="Button3" value="Button3" onclick="javascript:__doPostBack('Button3','')" id="Button3"/>
div>

我們定義的3個Button被轉化成3個能向Server端提交表單的<input > Tag, 但是他們提交表的方式卻不一樣,第一個以<input type="submit">的方式提交,後面兩個通過呼叫javascript的方式提交表單(<input type="button">)。對於一個System.Web.UI.WebControls.Button,預設採用第一種提交方式,但是我們通過設定UseSubmitBehavior屬性(這個屬性時ASP.NET 2.0新加的,1x沒有相應的設定),改變其表單提交的行為。

當用戶Click Button2的時候,呼叫__doPostBack,並傳入兩個引數:一個代表出發Event的物件的Unique name,也就是Button2的名稱,另一個描述Event的額外資訊的引數,這裡不需要,所以這裡是空字串。在__doPostBack中把這兩個引數賦值給兩個Hidden Field:__EVENTTARGET,__EVENTARGUMENT。然後向Server端提交表單,完成Postback。

然後我們來看看Server如何處理這個Postback,關於Web Page的生命週期在這裡就不詳細介紹了。Server端通過__EVENTTARGET這個hidden field的值找到對應的Server端的Control,通過Reflection確定該Control是否實現了System.Web.UI.IPostBackEventHandler Interface。如果該Control確實實現了該Interface,那麼呼叫Page的RaisePostBackEvent方法,這是一個Virtual的方法,可以被Override。我們來看該方法的定義。

[EditorBrowsable(EditorBrowsableState.Advanced)]
protectedvirtualvoid RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument)
{
    sourceControl.RaisePostBackEvent(eventArgument);
}

我們可以看到該方法直接呼叫該sourceControl的RaisePostBackEvent,並傳入一個eventArgument引數,在這個例子中sourceControl就是__EVENTTARGET對應的Web Control:Button2,eventArgument就是__EVENTTARGET對應的值:一個空字串。Button2的型別是System.Web.UI.WebControls.Button。我們來看看System.Web.UI.WebControls.Button中的方法是如何定義的:

protectedvirtualvoid RaisePostBackEvent(string eventArgument)
{
    
base.ValidateEvent(this.UniqueID, eventArgument);
    
if (this.CausesValidation)
    
{
        
this.Page.Validate(this.ValidationGroup);
    }

    
this.OnClick(EventArgs.Empty);
    
this.OnCommand(new CommandEventArgs(this.CommandName, this.CommandArgument));
}

這個方法也很簡單,先進行Validation,然後先後出發兩個Event:OnClick 和OnCommand,隨後呼叫對應的Event handler,這和我們的輸出結果是吻合的。

這基本上就是整個Postback的整個程式執行的過程,現在我們對我們的Page作一些小的有趣的改動,來驗證一下:

Client端和Server端進行互動的途徑就是提交表單(Form Submitting),而我們現在有兩種方式來提交表單:通過<input type="submit">控制元件;通過呼叫javascript:__doPostBack。基於這一點我們在Html中加了下面一段javascript: 

<script type="text/javascript">
    
function postback()
    

相關推薦

no