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

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

開篇:經歷了上一篇後,我們瞭解了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 }
View Code

   這裡,我們藉助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>
View Code

  ②後臺程式碼模擬從資料庫中取得資料集合並繫結到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 }    
View Code

  編譯生成後,通過檢視此頁面的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>
View Code

  (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();
        }
}
View Code

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

  在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學習者的我們,不能滿足於微軟為我們所提供的便利,要知其然也知其所以然,做一個上進的程式設計師,加油吧!

  校園招聘的大潮就快來臨,希望園子裡跟我一樣即將畢業的菜鳥們能夠好好複習基礎,在招聘中贏得一份好offer,實現自己的價值!

參考資料

  (1)楊中科,《特供2014版ASP.Net教程》,http://net.itcast.cn/subject/tegongnet/index.html

  (2)匿名未知,《狀態儲存機制之ViewState概述及應用》,http://www.jb51.net/article/33686.htm

  (3)popping_dancer,《ASP.Net原理篇之ViewState》,http://www.2cto.com/kf/201210/160413.html

  (4)玉開,《ASP.Net 4.0新特性-輸出更純淨的Html程式碼》,http://www.cnblogs.com/yukaizhao/archive/2010/05/22/asp-net-new-feature-pure-html.html

  (5)Infinities Loop,《ASP.Net ViewState詳解》,http://www.cnblogs.com/wwan/archive/2010/11/18/1880357.html

  (6)LifelongLearning,《ASP.Net 4.0中ViewState使用簡介》,http://www.csharpwin.com/dotnetspace/13220r6527.shtml

  (7)自由飛,《禁用VIEWSTATE之後(一)》,http://www.cnblogs.com/freeflying/archive/2009/12/28/1634229.html

  (8)MSDN,《瞭解使用ASP.NET AJAX進行區域性頁面重新整理》,http://msdn.microsoft.com/zh-cn/dd361854.aspx

  (9)xiaomin,《UpdatePanel工作原理》,http://www.cnblogs.com/xiaomin/archive/2011/11/01/2232215.html

  (10)浪子,《遠離UpdatePanel給我的噩夢》,http://www.cnblogs.com/walkingboy/archive/2007/01/09/615691.html

作者:周旭龍

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。