UpdatePanel招誰惹誰?
在前一篇文章裡,為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設計需求,注定無緣參與大型網站的建置,勢必不利前途(跟錢途),值得警惕!