1. 程式人生 > >ASP.Net WebForm溫故知新學習筆記:二、ViewState與UpdatePanel探秘

ASP.Net WebForm溫故知新學習筆記:二、ViewState與UpdatePanel探秘

ole htable nbsp 工具 utf cti abi divide 優點

原文地址:http://www.cnblogs.com/edisonchou/p/3901559.html

開篇:經歷了上一篇《aspx與服務器控件探秘》後,我們了解了aspx和服務器控件背後的故事。這篇我們開始走進WebForm狀態保持的一大法寶—ViewState,對其刨根究底一下。然後,再對曾經很流行的ASP.Net AJAX方案中的利器—UpdatePanel這個神奇的區域一探究竟。

一、隱藏的狀態—ViewState探秘

1.1 從Http的無狀態說起

  Http是一個無狀態協議,同一個會話的連續兩個請求互相不了解,它們由最新實例化的環境進行解析,除了應用本身可能已經存儲在全局對象中的所有信息外,該環境不保存與會話有關的任何信息

。另外,因為,瀏覽器和服務器之間是通過Socket進行通信,Http請求通常請求完畢就會關閉Socket連接,因此Http協議不會保持連接。如果保持連接會降低客戶端並發處理請求數,不保持連接又會降低處理速度(建立連接所需的時間會長一點);

PS:這裏我們可以這樣來理解:假如我們去一個大型商場購物購買某個產品,第一次去的時候是A銷售員接待了我們,帶領我們來到XX產品的櫃臺並為我們推薦了XX產品;等我們回去使用XX產品後,覺得XX產品真心不錯。第二次我們又去,但是這次卻找不到上次那個A銷售員了,相反商場分配了另一個B銷售員來接待我們,他不知道我們上次選擇了XX產品,相反它卻一個勁地向我們推薦YY產品並把我們帶向YY產品的櫃臺;這個時候,我們一般會說:我擦,把上次那個妹子給我叫來!

  基於Http協議的無狀態特性,我們在ASP.Net的開發中也會經常碰到這種情況:用戶上一次提交的東西,下次再提交時服務器就不記得了。很多時候,我們感到很不解?後來,我們發現原來每一次的請求服務器都開啟了不同的線程來處理,也就是說每次都會new一個XXX.aspx.cs中的類對象實例來進行處理(上一次new出來為我們處理的page對象也許早就被服務器銷毀了)。比如,我們在xxx.aspx.cs代碼中寫入了一個int類型的number成員(初始為0),每次請求我們都想讓這個number自增一下,然後重新返回給瀏覽器。但就是這麽一個簡單的夢想,我們卻無法輕易的實現。

技術分享

  那麽,到底怎麽來破呢?大神們已經為我們想好了策略,我們可以使用隱藏域字段、Cookie、Session等來保存狀態。而偉大的Microsoft還在ASP.Net中幫我們封裝了ViewState

,以至於我們在WebForm中進行PostBack操作時,都感覺不到服務器是無狀態的。

1.2 青春四處綻放—無處不在的ViewState

  (1)類似於Dictionary的一種數據結構

  如果你曾經使用過Dictionary或者Session的話,那麽你應該了解這種Key/Value的數據結構。這裏並沒有什麽高深的理論,ViewState通過String類型的數據作為索引。ViewState對應項中的值可以存儲任何類型的值(參數是Object類型),實施上任何類型的值存儲到ViewState中都會被裝箱為Object類型。

  例如,這裏我們可以改寫上面那個按鈕事件中的代碼:

技術分享 技術分享 技術分享
 1 protected void btnGetNumber_Click(object sender, EventArgs e)
 2 {
 3     //number++;
 4     //this.lblNumber.Text = number.ToString();
 5 
 6     object age = this.ViewState["age"];
 7     if (age == null)
 8     {
 9         age = 1;
10     }
11     else
12     {
13         age = Convert.ToInt32(age) + 1;
14     }
15     this.ViewState["age"] = age;
16     this.lblNumber.Text = age.ToString();
17 }
技術分享 技術分享

  這裏,我們借助ViewState存儲了age的狀態值,第一次來我給你返回1,後面再來我就加1再返回給你。於是,在上一節我們所提到的那個問題(無法記住上次的number值,每次都返回1)就解決了。

PS:ViewState不能存儲所有的數據類型,僅支持以下的這幾種: String、Integer、Boolean、Array、ArrayList、Hashtable以及一些自定義類型

  我們都知道,Dictionary和Session都是存儲在服務器端的。那麽,我們不禁要問,既然我們在服務器端給ViewState增加了一個Key/Value對,並返回給瀏覽器端,ViewState又是存儲在什麽位置的呢?

  (2)大隱隱於市的“頁面級”隱藏字段

  跟Session和Dictionary的存儲位置不同,ViewState的作用域是頁面,也就是說ViewState是存儲在瀏覽器的頁面之中的(這裏相比Session等,耗費的服務器資源較少,也算是ViewState的優點之一吧),當你關閉某個aspx文件後,那麽屬於這個aspx的ViewState也就不存在了。或許,這麽說來,我們還不是很了解,現在我們來實地看看。

技術分享

  ①首先,如果頁面上有一個runat="server"的form,當用戶請求這個頁面時,服務器會自動添加一個_ViewState的隱藏域返回給瀏覽器。但是,我們發現這個ViewState的value看起來像一串亂碼?這是為什麽呢?這是因為服務器在向瀏覽器返回html之前,對ViewState中的內容進行了Base64的加密編碼

  ②其次,當用戶點擊頁面中的某個按鈕提交表單時,瀏覽器會將這個_VIEWSTATE的隱藏域也一起提交到服務端;服務器端在解析請求時,會將瀏覽器提交過來的ViewState進行反序列化後填充到ViewState屬性中(比如下圖中,我們可以通過一個軟件將_VIEWSTATE解碼得到一個如下圖所示的樹形結構);再根據業務處理需要,從這個屬性中根據索引找到具體的Value值並對其進行操作;操作完成後,再將ViewState進行Base64編碼再次返回給瀏覽器端;

技術分享

  ③因此,我們可以得出一個結論:VIEWSTATE適用於同一個頁面在不關閉的情況下多次與服務器交互(PostBack)。這裏我們也可以通過下圖來溫習一下ViewState的流程,ViewState存放著“事故現場”,下次可以方便地“還原現場”,將無狀態的Http模擬成了有狀態的,也讓廣大的初學者了解不到無狀態的這個特性。

技術分享

1.3 喜歡就會放肆—又愛又恨的ViewState!

  事實上,除了我們手動在服務器端向ViewState屬性中添加的K/V對數據,我們在aspx.cs代碼中為某些服務器控件設置的值(例如:為Repeater設置DataSource中存入的數據集、為Label所設置的Text內容等,但不包括:TextBox、CheckBox、CheckboxList、RadioButtonList)都存入了ViewState中。這樣做的話,我們下次再向服務器提交請求時,現有表單中所有的服務器控件狀態都會記錄在ViewState中提交到服務器,在服務器端可以方便地對這些服務器控件進行有狀態的操作並返回,這無疑是讓我們歡喜的,因為方便了我們的開發過程,提高了我們的開發效率;

  但有人說:“喜歡就會放肆”,ViewState讓人又愛又恨啊。例如,在我們使用Repeater的過程中,WebForm會自動將DataSource(數據源,你可以理解為一個集合)存儲到ViewState中並返回給瀏覽器。可以參考下面的例子來實地理解一下:

  ①含有Repeater的aspx頁面:

技術分享 技術分享 技術分享
 1     <form id="form1" runat="server">
 2         <div align="center">
 3             <table class="test">
 4                 <tr class="first">
 5                     <td>
 6                         ID
 7                     </td>
 8                     <td>
 9                         產品名稱
10                     </td>
11                     <td>
12                         產品描述
13                     </td>
14                     <td>
15                         刪除
16                     </td>
17                 </tr>
18                 <asp:Repeater ID="repeaterProducts" runat="server">
19                     <ItemTemplate>
20                         <tr>
21                             <td>
22                                 <%#Eval("Id") %>
23                             </td>
24                             <td>
25                                 <%#Eval("Name") %>
26                             </td>
27                             <td>
28                                 <%#Eval("Msg") %>
29                             </td>
30                             <td>
31                                 <a href=‘Product.ashx?Action=Delete&Id=<%#Eval("Id") %>‘>刪除</a>
32                             </td>
33                         </tr>
34                     </ItemTemplate>
35                 </asp:Repeater>
36             </table>
37         </div>
38     </form>
技術分享 技術分享

  ②後臺代碼模擬從數據庫中取得數據集合並綁定到Repeater中:

技術分享 技術分享 技術分享
 1 protected void Page_Load(object sender, EventArgs e)
 2 {
 3     if (!IsPostBack)
 4     {
 5         this.repeaterProducts.DataSource = this.GetProductList();
 6         this.repeaterProducts.DataBind();
 7     }
 8 }
 9 
10 private IList<Product> GetProductList()
11 {
12     IList<Product> productList = new List<Product>();
13     productList.Add(new Product() { Id = 1, Name = "康師傅方便面", Msg = "就是這個味兒!" });
14     productList.Add(new Product() { Id = 2, Name = "統一方便面", Msg = "還是那個味兒!" });
15     productList.Add(new Product() { Id = 3, Name = "白象方便面", Msg = "大骨濃湯啊!" });
16     productList.Add(new Product() { Id = 4, Name = "日本方便面", Msg = "不只是愛情動作片!" });
17     productList.Add(new Product() { Id = 5, Name = "臺灣方便面", Msg = "馬英九誇我好吃!" });
18 
19     return productList;
20 }    
技術分享 技術分享

  編譯生成後,通過查看此頁面的html代碼,可以明顯看到一長串的_VIEWSTATE隱藏域。將此_VIEWSTATE復制到ViewStateDecoder中進行反編碼,可以發現它確實存儲了Repeater中的數據集合。這裏我們不禁要問:展示數據既然已經渲染成了html,為何還要存儲在ViewState隱藏域中?如果我們的數據集合是一百行、一千行數據的話,那ViewState隱藏域豈不很大(100k?200k?)?但不幸的是,這是ViewState的設計機制,要想依靠它來保持狀態,它就會將服務器控件的狀態包括數據集合都存儲到其中,在瀏覽器和服務器之間來回傳遞保持狀態。

技術分享

技術分享

  這裏就涉及到網站的性能問題的探討了:由於ViewState存儲在頁本身,因此如果存儲較大的值,用戶請求顯示頁面的速度會減慢(這對於互聯網系統來說,就是一個噩夢。你會選擇一個1秒內響應的網站瀏覽還是5秒內響應的網站?)。又因為ViewState會隨同Form表單一同回傳給服務器,如果ViewState很大的話,Http報文也會很大,網站流量消耗也會增大。

  那麽,有沒有一種方法可以讓ViewState克制一下呢?別急,請看下面的介紹。

1.4 但愛就是克制—禁用還是不禁用ViewState?

  剛剛說到,因為ViewState會一定程度上影響性能,所以我們可以在不需要的時候禁用 ViewState。默認情況下 ViewState 將被啟用,並且是由每個控件(而非頁面開發人員)來決定存儲在 ViewState 中的內容。有時,這一信息對應用程序並沒有什麽用處(例如上面提到的Repeater的數據集合,已經渲染生成了html顯示,還存儲了一份副本在ViewState裏邊)。盡管也沒什麽害處,但卻會明顯增加發送到瀏覽器的頁面的大小。因此如果不需要用ViewState,最好還是將它關閉,特別是當 ViewState 很大的時候。當然,ViewState幫我們實現了某些服務器控件狀態保持,因此在非必需的情況下,還是可以適度使用的,特別是在開發企業內部信息系統的場景。

  那麽,怎樣來禁用ViewState呢?禁用ViewState又有什麽策略呢?下面我們一一來探討。

  ①頁面級禁用ViewState:在aspx的首部的Page指令集中添加EnableViewState="false",該頁面中所有控件的狀態都不會存入ViewState的,頁面一下就會清爽許多;

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="RepeaterViewState.aspx.cs"
    Inherits="WebFormDemo.RepeaterViewState" EnableViewState="false" %>

  禁用後,再次查看生成的html代碼,我們會發現:咦,_VIEWSTATE還在那兒,但是明顯比先前的體積小了不少

技術分享

  再將這個瘦身後的_VIEWSTATE復制到ViewStateDecoder中進行反編碼查看,我們會發現,只保存了一個最基本的信息,Repeater的那些數據集合沒有存入進去了。

技術分享

PS:為什麽禁用ViewState之後,頁面源代碼中仍然有_VIEWSTATE的隱藏域

這是因為就算禁用了viewstate,aspx頁面中還是會有一個服務器控件在那裏使用,這就是<form runat="server">。這時,如果你將form去掉runat="server",將其變為普通html標簽,那麽頁面就幹凈了,從此_VIEWSTATE這個隱藏域徹底消失在你的頁面中。

  ②控件級禁用ViewState:在某些場景中,我們只希望禁用某個控件(例如Repater)的ViewState,其他控件仍然通過ViewState保持狀態。這時,我們可以給指定的控件設置一個屬性EnableViewState="false"即可;

<asp:Repeater ID="repeaterProducts" runat="server" EnableViewState="false">
</asp:Repeater>

  ③全局級禁用ViewState:園子裏的大神老趙(Jeffrey Zhao)曾經說過,“我如果新建一個WebForm項目,做的第一件事情就是去Web.config中將enableViewState設置為false從而將ViewState全局關閉”。那麽,我們如果希望將網站中所有頁面的ViewState都禁用,總不可能去一個一個頁面得修改Page指令吧?ASP.Net為我們提供了一個配置,我們只需要在Web.config的system.web中增加一句配置即可:

<pages enableViewState="false" />

PS:開發中也可以采用大神老趙的做法,先禁用,再選擇性啟用,畢竟沒有非要ViewState才能幹成的事兒!

  ④真正的禁用ViewState:剛剛我們的三種方法實踐後,在頁面還是出現_VIEWSTATE的隱藏域,盡管它保留了最基本的信息。那麽,我們可能會問?怎樣才能徹底地真正地禁用ViewState,根本就別給我生成_VIEWSTATE的隱藏域。答案是有的,將<form runat="server"/>的runat="server"去掉,就不會出現了,但那樣又會偏離WebForm的開發模式,大部分的服務器控件都無法正常使用,開發效率又會有所損失。

  綜上所述,在實際開發中應該權衡利弊,特殊情況特殊分析(到底這個場景該不該禁用ViewState),選擇是否禁用ViewState,采用何種方式禁用ViewState。對於ViewState的探秘本篇就到此為止,由於我本人理解的也不是很深刻,所以希望各位園友如果有理解,可以回復出來大家探討共同進步。

二、飛來的利器—UpdatePanel探秘

2.1 從一個簡單四則運算計算器說起

  假如有以下一個場景,我們要做一個簡單的四則計算器。aspx頁面代碼和後端邏輯代碼如下:

  (1)aspx頁面代碼

技術分享 技術分享 技術分享
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>AJAX計算器</title>
</head>
<body>
    <form id="form1" runat="server">
    <div align="center">
        <asp:TextBox ID="txtNumber1" runat="server"></asp:TextBox>
        <asp:DropDownList ID="ddlFunc" runat="server">
            <asp:ListItem Value="0">+</asp:ListItem>
            <asp:ListItem Value="1">-</asp:ListItem>
            <asp:ListItem Value="2">*</asp:ListItem>
            <asp:ListItem Value="3">/</asp:ListItem>
        </asp:DropDownList>
        <asp:TextBox ID="txtNumber2" runat="server"></asp:TextBox>
        <asp:Button ID="btnGetResult" runat="server" Text="=" Width="50" 
            onclick="btnGetResult_Click" />
        <asp:Label ID="lblResult" runat="server" Text="" Font-Bold="true"></asp:Label>
    </div>
    </form>
</body>
</html>
技術分享 技術分享

  (2)後置邏輯代碼

技術分享 技術分享 技術分享
public partial class AjaxCalculator : System.Web.UI.Page
{
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void btnGetResult_Click(object sender, EventArgs e)
        {
            int number1 = Convert.ToInt32(this.txtNumber1.Text);
            int number2 = Convert.ToInt32(this.txtNumber2.Text);
            int result = 0;
            switch(this.ddlFunc.SelectedValue)
            {
                case "0":
                    result = number1 + number2;
                    break;
                case "1":
                    result = number1 - number2;
                    break;
                case "2":
                    result = number1 * number2;
                    break;
                case "3":
                    if(number2 == 0)
                    {
                        throw new DivideByZeroException("除數不能為0!");
                    }
                    result = number1 / number2;
                    break;
            }
            this.lblResult.Text = result.ToString();
        }
}
技術分享 技術分享

  生成後運行該頁面,可以達到以下的效果。我們輸入兩個數字後,選擇是加法、減法、還是乘除法後,點擊=按鈕,即可刷新頁面顯示運算結果。

技術分享

  在WebForm中,每一次點擊runat="server"的按鈕都會將調用form.submit將請求提交到服務器,服務器會返回新的頁面html進行頁面重繪。這是一個整頁的刷新操作,不符合AJAX的風格需求。因此,我們想要將其改為AJAX版本的,除了使用基本的XMLHttpRequest外,我們還可以使用基於JQuery的AJAX方案,這些都是輕量級的原生態的AJAX技術方案。但我們偉大的微軟(我哭啊,真是為我們考慮啊,連AJAX方案都為我們解決了,而且還提供了AJAX控件供我們使用,我們拖控件的習慣可以用到AJAX方案上了!!!)還為我們提供了一套叫做ASP.Net AJAX的技術方案,通過這套方案,我們可以在ASP.Net很容易地實現AJAX效果,甚至都不需要我們懂JavaScript。因此,也就出現了前些年,很多WebForm開發者陸續使用ASP.Net AJAX Extension進行AJAX開發,紛紛表示:AJAX如此簡單,我等豈能不會?但是,雖然它簡單易行,由於其性能問題一直被人詬病,而我們這些菜鳥也未能了解其性能問題的原因,本著知其然也知其所以然的目標,現在我們來使用它並剖析它一下。

2.2 天上掉下個林妹妹—使用UpdatePanel控件

  不得不說,UpdatePanel真的是天上掉下的林妹妹,一個神奇的控件!有了它,我們可以將頁面中需要進行局部刷新的內容放到其ContentTemplate中,一個需要整頁刷新的操作便可以成為局部刷新。現在,我們首先來使用其改造剛剛的簡單四則計算器頁面。

  (1)加入UpdatePanel,並將計算器html內容拖入ContentTemplate中

技術分享 技術分享
 <form id="form1" runat="server">
    <div align="center">
        <asp:ScriptManager ID="scriptManager" runat="server">
        </asp:ScriptManager>
        <asp:UpdatePanel ID="updatePanel" runat="server">
            <ContentTemplate>
                <asp:TextBox ID="txtNumber1" runat="server"></asp:TextBox>
                <asp:DropDownList ID="ddlFunc" runat="server">
                    <asp:ListItem Value="0">+</asp:ListItem>
                    <asp:ListItem Value="1">-</asp:ListItem>
                    <asp:ListItem Value="2">*</asp:ListItem>
                    <asp:ListItem Value="3">/</asp:ListItem>
                </asp:DropDownList>
                <asp:TextBox ID="txtNumber2" runat="server"></asp:TextBox>
                <asp:Button ID="btnGetResult" runat="server" Text="=" Width="50" OnClick="btnGetResult_Click" />
                <asp:Label ID="lblResult" runat="server" Text="" Font-Bold="true"></asp:Label>
            </ContentTemplate>
        </asp:UpdatePanel>
    </div>
</form>
技術分享 技術分享

  (2)運行該頁面,通過開發人員工具查看Http請求

技術分享

  通過查看請求報文,我們了解到此次的請求響應不再是返回整頁的html內容,而只是我們放在了UpdatePanel裏面的html內容,頁面也沒有再刷新,於是不禁感嘆一句:AJAX,So easy!媽媽再也不用擔心我的頁面了!

2.3 直到看見XmlHttpRequest才是唯一的答案—UpdatePanel原來如此

  正當我們沈浸在UpdatePanel為我們提供的神奇的AJAX世界裏時,我們不禁對UpdatePanel為我們做了哪些工作產生了興趣。

  (1)首先,我們知道AJAX的核心對象是XmlHttpRequest,那麽原生態的AJAX請求的JS方法是如何寫的呢?

技術分享 技術分享
function ajax(url, onsuccess) {
    var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject(‘Microsoft.XMLHTTP‘); //創建XMLHTTP對象,考慮兼容性。XHR
    xmlhttp.open("POST", url, true); //“準備”向服務器的xx.ashx發出Post請求(GET可能會有緩存問題)。這裏還沒有發出請求

    //AJAX是異步的,並不是等到服務器端返回才繼續執行
    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState == 4) //readyState == 4 表示服務器返回完成數據了。之前可能會經歷2(請求已發送,正在處理中)、3(響應中已有部分數據可用了,但是服務器還沒有完成響應的生成)
        {
            if (xmlhttp.status == 200) //如果Http狀態碼為200則是成功
            {
                onsuccess(xmlhttp.responseText);
            }
            else {
                alert("AJAX服務器返回錯誤!");
            }
        }
    }
    //不要以為if (xmlhttp.readyState == 4) {在send之前執行!!!!
    xmlhttp.send(); //這時才開始發送請求。並不等於服務器端返回。請求發出去了,我不等!去監聽onreadystatechange吧!
}
技術分享 技術分享

  (2)其次,通過查看運行頁面的html,我們可以發現加入UpdatePanel後,我們的html中多了這麽幾個js引用。

技術分享

  (3)既然我們知道要發AJAX請求,必然會涉及到XmlHttpRequest。那麽,我們就在這幾個js中取看看是否有涉及到XmlHttpRequest。通過查看,我們找到了這樣一個似曾相識的js方法:

技術分享 技術分享
function Sys$Net$XMLHttpExecutor$executeRequest() {
        /// <summary locid="M:J#Sys.Net.XMLHttpExecutor.executeRequest" />
        if (arguments.length !== 0) throw Error.parameterCount();
        this._webRequest = this.get_webRequest();
        if (this._started) {
            throw Error.invalidOperation(String.format(Sys.Res.cannotCallOnceStarted, ‘executeRequest‘));
        }
        if (this._webRequest === null) {
            throw Error.invalidOperation(Sys.Res.nullWebRequest);
        }
        var body = this._webRequest.get_body();
        var headers = this._webRequest.get_headers();
        this._xmlHttpRequest = new XMLHttpRequest();
        this._xmlHttpRequest.onreadystatechange = this._onReadyStateChange;
        var verb = this._webRequest.get_httpVerb();
        this._xmlHttpRequest.open(verb, this._webRequest.getResolvedUrl(), true );
        this._xmlHttpRequest.setRequestHeader("X-Requested-With", "XMLHttpRequest");
        if (headers) {
            for (var header in headers) {
                var val = headers[header];
                if (typeof(val) !== "function")
                    this._xmlHttpRequest.setRequestHeader(header, val);
            }
        }
        if (verb.toLowerCase() === "post") {
            if ((headers === null) || !headers[‘Content-Type‘]) {
                this._xmlHttpRequest.setRequestHeader(‘Content-Type‘, ‘application/x-www-form-urlencoded; charset=utf-8‘);
            }
            if (!body) {
                body = "";
            }
        }
        var timeout = this._webRequest.get_timeout();
        if (timeout > 0) {
            this._timer = window.setTimeout(Function.createDelegate(this, this._onTimeout), timeout);
        }
        this._xmlHttpRequest.send(body);
        this._started = true;
}
技術分享 技術分享

  由以上的方法名我們可以猜到,此方法是一個執行AJAX請求的方法。在此方法中,創建了XmlHttpRequest對象,也使用了open方法指明以GET還是POST方法向服務器哪個處理程序發送請求,並且也為該請求指定了請求成功後需要執行的回調函數方法(onreadystatechange),最後調用send方法正式發送請求

  由此,我們可以初步分析出一個結論:UpdatePanel本質還是幫我們封裝了以XmlHttpRequest為核心的一系列方法幫我們將CodeBehind中的同步事件變為了異步操作,並通過DOM更新指定的HTML內容,使得我們可以方便地實現AJAX效果

  但是,我們也不由發出感嘆:本來可以很簡單地使用XmlHttpRequest來實現的東西,為什麽使用UpdatePanel會引入這麽多js,並且為我們返回的東西還是那麽多(比如上面的例子,我只需要的數據是一個結果,卻給我返回一部分無用的html,還有一系列的hiddenId之類的數據)。在對性能要求較高的應用場合,如果使用UpdatePanel來實現AJAX會增加服務器的負載,並且會消耗掉不必要的網絡流量(比如每次請求都會來回都會發送ViewState裏的數據,在性能和數據量上都會造成損失)。園子裏的浪子曾經在他的博文《遠離UpdatePanel帶給我的噩夢》裏邊寫到:“UpdatePanel在頁面小的時候還是很好用的,而當頁面控件數不斷上升的時候,UpdatePanel就開始直線下降,我們現在頁面有4,5百個控件,每做一次PostBack需要長達15秒鐘之長,實在讓人無法忍受。”

  那麽,有木有方式可以替換UpdatePanel呢?其實答案很簡單,那就是使用基於XmlHttpRequest的js方法,再加上一定的js回調函數即可。這就要求我們掌握javascript,不能只做拖UpdatePanel控件的程序員。現在基於js的JQuery庫也早已為我們封裝了XmlHttpRequest,提供了ajax開發的一系列方法供我們調用,相當於UpdatePanel的“重量級”來說,可謂是輕了不少,是一個“輕量級”的AJAX開發方式。通過借助jQuery Ajax+ashx可以方便地在.Net中進行Ajax開發,並且具有不錯的性能,這也是我實習所在的企業中經常用到的方式。

三、學習總結

  本篇主要學習了WebForm中的狀態保持法寶—ViewState,以及曾經的ASP.Net AJAX方案的利器—UpdatePanel,雖然一直在說這個不好,那個別用。但是,微軟之所以為我們提供了這些東西,肯定有它存在的理由,並不一定都是不好的東西。所謂利器在手,沒有一點內功心法的人還是使用不好它,無法發揮出其100%的優勢。因此,身為.Net學習者的我們,不能滿足於微軟為我們所提供的便利,要知其然也知其所以然,做一個上進的程序員,加油吧!

ASP.Net WebForm溫故知新學習筆記:二、ViewState與UpdatePanel探秘