在前一篇文章裡,為ASP.NET AJAX Client Templates做了個開場,某些人心中或許已浮現幾絲驚恐,不斷吶喊--為什麼? 為什麼有人要對UpdatePanel趕盡殺絕? UpdatePanel用得好好的,為什麼忽然又要改朝換代學新東西? 沒了UpdatePanel,叫我們不會寫Javascript又被老闆要求搞什麼鬼AJAX的人去死嗎?

其實,不用過度驚慌,沒有一無是處的技術,只有用錯場合的白目。UpdatePanel並非萬惡不赦,只是在應用它之餘,也要通曉它的優點與罩門,儘可能找到可以展現優點的時機,避免會曝露罩門的場合。

UpdatePanel最大的賣點,應該是讓ASP.NET Developer可以在不懂Javascript及HTML端細節的前題下,靠著拖拉控件,用已熟悉的Server-Side Event就把原本死板的PostBack式網頁,瞬間升級成又酷又炫的AJAX風格網頁。瞧! 網頁上內容不斷翻新,螢幕都不會閃耶! 而且我兩分鐘就寫好了,你們這些用Javascript搞AJAX的,連更新資料的Web Service還沒動工哩~~

的確,UpdatePanel的架構簡單、邏輯集中(不需另外寫Web Page/Service供前端呼叫)、開發簡便快速,加上完全用Server-Side事件解決,只要會寫ASP.NET的開發者就能上手,又不易出錯,門檻頗低(依個人經驗,不會寫Javascript的ASP.NET開發者比比皆是!),優點多多。

這樣看來,UpdatePanel不是很完美嗎? 罩門在哪裡? 效能!!

UpdatePanel背後的原理,是用HttpRequest的方式執行PostBack,肥大的ViewState要照送,完整的WebPage處理流程也要全程跑完,差別是網頁只是會產生UpdatePanel裡面的HTML Code傳回。(換句話說,你要是整頁包在一個超大的UpdatePanel裡,傳的資料量就跟PostBack整個網頁相去不遠,因此要把握"UpdatePanel像比基尼,愈小愈好"的原則。)

讓我來示範一下。

我寫了一個網頁,放了一個鈕Button1用來更新Label1顯示時間,利用SqlDataSource將AdventureWorks資料庫的產品資料傳給GridView1並支援分頁顯示,當選取某項產品時,利用DetailsView1顯示產品明細,並顯示產品照片。

大部分的東西都用宣告做掉了,要寫的Code很少!

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
            Label1.Text = DateTime.Now.ToString("HH:mm:ss");
 
    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        Label1.Text = DateTime.Now.ToString("HH:mm:ss");
    }
 
    protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
    {
        DetailsView1.PageIndex = GridView1.SelectedRow.DataItemIndex;
    }

實際跑一下,分別按下Button1、GridView1翻到第2頁,並選取其中一個物項目。用HttpWatch Pro觀察,可以看到四次傳輸,下載資料量都是7KB近8KB,第二次後為PostBack,上傳資料傳輸量近3KB,主要是要傳送ViewState的緣故。

好,讓我們加上UpdatePanel,用一個UpdatePanel將Button1, Label1, GridView1, DetailsView1通通包起來,Server-Side的Code一行都不用改,馬上升級成AJAX動態更新,網頁閃動Bye-Bye,改寫過程之簡單,簡直像魔法。

再觀察一下資料傳輸量,我們一樣看載入、按Button1、換頁、看產品詳情四次傳輸。

首次載入時,網頁HTML約9KB,並額外下了三個js約90KB,但js部分未來可由Cache取得,不會每次重傳。但接下來的按Button1、換頁及檢視產品過程,雖然網頁不再閃動,傳輸的資料量為上傳2.4KB,下載7KB,跟PostBack十分相近。也就是說,雖然換上了AJAX的皮,骨子裡跟PostBack造成的網路及伺服器負擔是差不多的。

等等,剛才不是有某個色胚說什麼"UpdatePanel要像比基尼,愈小愈好"? 我們來把這件連身衣改成三點式好了! 分別用一個UpdatePanel(紅框)包住Button1及Label1,一個UpdatePanel(綠框)包住GridView1,一個UpdatePanel(藍框)包住DetailsView1,並將三個UpdatePanel.UpdateMode改為Conditional,分別由Button1.Click、GridView1.PageIndexChanged、GridView1.SelectedIndexChanged事件觸發:

拆成獨立UpdatePanel,讓我們可以每次更新一小塊,但由測試結果來看,每個動作上傳的2.5KB省不了,按Button1、換頁、檢視產品還是分別產生了2.5KB、5.8KB、3.4KB的資料下載量。最過分的是單單更新Label1.Text幾個字元也要傳回2.5KB,其中超過95%來自ViewState。

由以上的實驗來看,拆解出小而獨立的多個UpdatePanel,雖可以減少部分資料下載量,但每次更新,上傳跟下傳的ViewState終究還是省不了的。在上面的例子裡,即便UpdatePanel內空空如也,去2.5KB、回來2.5KB也得行禮如儀。同時,這種架構採行了全頁重新執行的概念,因此即便拆成多個UpdatePanel,同一時間內只允許一個UpdatePanel進行更新。

可以想見,若你的網頁會放在Internet上給成千上萬的使用者點閱,每次更新幾個字元就要來回5KB的資料量,頻率一高,對於頻寬就是沈重的負擔,何況處理這個大量的資料來回,對Client與Server都要耗費無謂的CPU、Memory、I/O資源,從機車一點的角度來看,亦不符合"節能減碳"的環保理念。在這種情境下,為求開發過程簡便快速、擔心開發者多學Javascript太過勞累就不再是重要的考量因素,如何用最少的資料傳輸量達成同樣的效果,才是王道,於是,像ASP.NET AJAX Client Templates這種主打輕巧的設計概念就應運而生了。

我們並不需完全抺煞UpdatePanel的價值。不可否認地,UpdatePanel的簡單易學、低技術門檻,仍是不可取代的,在對效能要求不高(尤其是LAN裡)、用量不大的情境下,拖拖拉拉寫個兩行就做出漂亮的AJAX網頁,有何不可? 只是,身為ASP.NET開發者,如果永遠停留在不學Javascript、只會用UpdatePanel的層次,就沒有能力滿足高承載網站的AJAX設計需求,注定無緣參與大型網站的建置,勢必不利前途(跟錢途),值得警惕!


Comments

# by 草莓菌

顶,有见解。我用UpdaePanel都快郁闷了。

# by Billy

在 Pro ASP.net 3.5 in C# 2008 一書中,有以下的一段,留下給各位參考: When you use the UpdatePanel, you don't reduce the amount of bandwidth being used or the time taken to receive the response from the server, because the entire page is still sent. The only difference is that the page is updated without a distracting flicker.

# by 海角147號

我是完全捨棄了 UpdatePanel 以及 ASP.NET的Control 因為實在不是很方便! 我目前還有在用的是 FileUpload 相關的..!!

# by 路人甲

那麼...以同一個範例, 樓主可以用jquery實現一下, 再測試連接速度嗎?

# by Jeffrey

to 路人甲,我在RUN!PC有篇文章做過較完整的比較。http://www.runpc.com.tw/content/main_content.aspx?mgo=181&fid=E03

# by tinydonut

UpdatePanel Tips and Tricks http://msdn.microsoft.com/en-us/magazine/cc163413.aspx

# by tinydonut

Improving UpdatePanel Performance with Trace=”true” http://www.schnieds.com/2008/02/improving-updatepanel-performance-with.html

# by tinydonut

UpdatePanel無法有效改善Performance的原因 http://www.dotblogs.com.tw/hatelove/archive/2009/02/10/7091.aspx simple Solution: 用 javascript呼叫server端的method http://www.dotblogs.com.tw/hatelove/archive/2009/01/05/6639.aspx

Post a comment