加入RUN!PC粉絲團
最近新增的精選文章
 
最多人點閱的精選文章
 
 
精選文章 - 開發技術
分享到Plurk
分享到FaceBook
 
Pure AJAX之道(下)
ASP.NET AJAX Templates整合應用
文/圖 李明儒.責任編輯/洪羿漣

在前期文章中,介紹了透過ASP.NET AJAX Templates輕鬆將Javascript資料物件轉化為HTML表格的方法。接下來,我們將延伸製作出支援Master-Detail連動,並由WCF取得資料來源的整合應用。

除了使用Javascript進行Data Binding外,ASP.NET AJAX Templates也支援透過標籤宣告完成設定,試圖再次實現搞AJAX不用寫Javascript的目標。實作重點如下:

1. 使用宣告法時,取消元素隱藏的工作由Client Template Library函數完成,而自動取消的關鍵在於樣版元素要指定名為"sys-template"的CSS Class。
2. 在body上要註冊sys與dataview兩個命名空間(Namespace),如:「body xmlns:sys="javascript:Sys" xmlns:dataview=" javascript:Sys.UI.DataView" sys:activate="*"」,其中sys:activate可以指定文件載入後要自動啟用的元素有哪些,指定方式是傳入元件的ID,如有多個則以逗號分隔,「*」則代表全部。
3. 要設為Template的元素可指定以下屬性:
●data:資料來源為Javascript物件時,直接用此宣告,但因為嵌入Javascript語法,記得加上雙層大括號,寫成{{ objName }}。
●datasource:如資料來源是Web Service或ADO.NET Data Service時,在此指定Javascript中的代理資料物件。
●serviceuri:提供資料來源服務的URI。(可能是Web Service,WCF或ADO.NET Data Service)
●query:指定取得資料的函數名稱,它會被組合成呼叫服務的URI中。也就是說,WCF函數如果需要傳入參數,得改成可透過URI方式傳入。
●itemtemlate:適用於要指定另一個元素做為樣版時。
●selecteditemclass:當支援選取模式,被選取項目的CSS Class名稱。
4. 要使用選取功能,可在要當作點選目標的元素加入sys:command="select"宣告,點選後就會發現它的CSS變成上述指定的selecteditemclass。同時為增加友善度,提示User可以點選,我們透過CSS為讓元素加上底線、改變Cursor。

把全部的東西組在一起,我們得到如程式1的結果。


程式1


點選每一列的Id欄可以選取該列改變其背景色,進一步,我們還可以將「選取」動作擴充成為Master-Detail連動。(圖1)


圖1:宣告式AJAX Templates執行結果。



Data Binding與Master Detail連動
之前的ASP.NET AJAX Templates介紹都集中在如何將資料反應到顯示元素上。在WebControl Template中,我們可以選擇用Eval或Bind來連結資料,當使用Bind時,更改Template裡的資料,會反應回原始的資料來源上,這在ASP.NET AJAX Client Templates也做得到!

進一步來說,ASP.NET AJAX Client Templates的Binding寫法有三種:
1. One-Way, One-Time:即先前示範的{{ propName }}表示法,set_data時會將資料值寫入,之後就不再有任何互動。
2. One-Way:要寫成{binding propName},set_data後,若當初提供資料來源的Javascript物件變動,該值亦會自動更新。 最主要應用於Master-Detail的情境。
3. Two-Way:一樣是寫成{binding propName},但若同一屬性用在兩個HTML元素上,則更改其中一個,另一個也會跟著變化。

接下來,我們將前述宣告式AJAX Templates的例子做些修改,改裝成Master-Detail形式,並透過Two-Way Binding加上酷炫的編輯功能。

首先,原本的Table維持不變,但要多加一個dataview:sys-key="dataViewObjName"的屬性,如此,便可利用這個變數名稱存取背後的Sys.UI.DataView物件。而這個物件,也將會是Detail View要Bind的對象。

我們建立一個div內包fieldset做為簡陋的Detail View展示:




值得注意的是,Score分數的部分,我們用了input,value則寫成{binding Score},如此,當數字內容修改,就會反映回來源物件的Score屬性。但原先Table中我們寫的是「td style="text-align: right;">{{Score.format("N2")}} /td」,這是One-Time Binding,不會即時反應資料值的變化,因此得改成{binding Score}的格式。

但問題來了,原來我們對數字做了格式化,加上千位號以及限定小數兩位,binding表示法裡必須直指Score,而不能用Score.format("N2")。要解決這個問題,要靠convert函數,其表示法為{binding propName, convert=convertFuncName}。在範例裡,我們新增一個函數fmtNum,原本的Binding語法則改寫成「td style="text-align: right;">{binding Score, convert=fmtNum} /td」:




如圖2所示,按了Id欄位,下方Detail View就會即時顯示所選取的項目,而修改Score後,修改後的分數會立即回饋到上方的Master View。


圖2:Master-Detail連動效果與資料同步更新。



由WCF提供資料來源
到目前為止,我們示範的ASP.NET AJAX Client Templates寫法,為了簡化起見,資料來源都是以Javascript [ { ... }, { ... } ]的方式就地打造物件陣列。在實務上,我們多半會另外撰寫一個Web Page、Web Service或WCF作為資料來源。

在微軟構築的藍圖中,WCF已內建Client Script支援功能,整合的緊密度讓人驚豔,可當作建構AJAX後端的首選。更進一步,若資料來源更直接地映對到資料庫DataTable時,則ADO.NET Data Service還能提供更密切的整合,甚至還有前端的MicrosoftAjaxAdoNet.js提供一缸子的Javascript Function協助,寫起Code來更加得心應手。在此我們先以WCF為例。

延續先前的範例,我們打算將資料來源改由另一個WCF服務提供,不再只是透過Javascript就地建立物件陣列頂替。目標還是要取得一個有Id, Name, Score, RecTime屬性的人員資料陣列,只是要改用WCF實作。

首先,用VS2008在ASP.NET專案中新增一個AJAX-enabled WCF Service(如圖3),命名為PeopleSource.svc,VS2008會幫你產生PeopleSource.svc, App_Code\PeopleSource.cs。


圖3:在Visual Studio 2008中新增AJAX-enabled WCF Service。


AJAX-enabled WCF Service與一般WCF Service在web.config裡設定不太相同,會設定enabledWebScript,好開啟WCF內建支援Client Script的功能。另外,新增AJAX-enabled WCF Service時也不再另外安插Interface。

接著,我們把PeopleSource.cs修改成需要的樣子,如程式2,傳回List Person,Person是我們自訂的物件,透過[DataContract]、[DataMemeber]宣告,可以自動被WCF轉換成JSON格式。


程式2:PeopleSource.cs


接著,我們修改先前的ASPX,在ScriptManager中加入:




神奇的事發生了,打入Darkthread(在PeopleSource.cs裡宣告的ServiceContract Namespace),VS2008自動提示可用的Interface、Method名稱、呼叫參數。


圖4:WCF支援VS2008 Javascript Intellisense。


將前面的ASPX內容稍作修改,主要加入ServiceReference及呼叫Darkthread.PeopleSource.GetPeople。WCF自動產生的Javascript端GetPeople函數,第二參數onSuccess要宣告一個Function接收WCF傳回的結果。函數只有一個呼叫參數data,即為WCF端所return的物件。由於GetPeople宣告的傳回物件是List Person,在Javascript端,會透過JSON自動轉成有物件陣列,而物件有哪些屬性,會以先前在PeopleSource.cs裡Person宣告[DataMemeber]的屬性為準,也就是Id, Name, Score, RecTime。

如此一來,data跟上回Hard-Coding建出的物件陣列完全相同,我們直接dv.set_data(data)即可完成Client Side Binding,輕鬆愉快。(程式3)


程式3


執行網頁,我們得到與上回一模一樣的結果,不同的是,資料來源已改由WCF提供。

WCF函數傳回的List T可以當場轉成立即可用的Javascript Object Array,直接做為ASP.NET AJAX Templates的資料來源,這也可以應用在LINQ傳回的資料物件上,非常方便。


拼湊全貌
再回頭看前期所提的產品瀏覽UpdatePanel例子,我們目前已經掌握了AJAX Templates呼叫WCF所提供的資料來源、Binding、Master-Detail連動等技術,便可用AJAX Templates的新方法,實作與UpdatePanel相同的效果,再比較二者傳輸效率上的差異。

首先,我們要準備支援換頁的資料來源WCF服務,借助LINQ to SQL,這件事並不困難。建立一個DBML,僅加入我們展示所需Product、ProductPhoto及ProductProductPhoto資料表即可。(如圖5)


圖5:建立所需的DBML。


由於WCF會自動將傳回結果轉為JSON格式,但前題必須是強型別物件。LINQ to SQL裡雖有Product資料物件,但我們要用的欄位只有幾個,所以我們另外設計一個較精簡的物件ProductInfo,以提高傳輸效率:




除此之外,GridView支援分頁顯示功能,在我們的Pure AJAX版也要比照。因此每次查詢資料時,應指定每頁的大小及要顯示的頁數,同時前端也必須知道總頁數,以便顯示頁次切換。由此看來,查詢函數不能只傳回ProductInfo陣列,還必須加入總頁數、目前所在頁次等資訊。我們設計另一個ProductData類別,當成與前端溝通的資料物件:




查詢資料的核心不難寫,主要是以LINQ語法為主,並利用Skip(), Top()來做分頁效果,為了補足先前UpdatePanel範例中取得伺服器時間的功能,再補上另一個GetNow()負責傳回現在時間,如程式4。




接著我們把焦點移回到前端,在網頁上放上兩個Table,一個用來顯示產品清單,姑且稱之為MasterView,映對到先前UpdatePanel範例中的GridView1;右側Table則用來顯示產品詳細資料及照片,角色如同UpdatePanel範例中的DetailView1,在此稱之為DetailView。

注意,此處做了一個取捨。在MasterView中,只用到ProductNum及Name兩個欄位,當使用者點選其中一筆時,才會在DetailView顯示完整的資料細節。在前面介紹Master-Detail連動時,我們發現dataview:data="{binding selectedData, source={{ master }}}"的寫法,是直接找到當時已存在記憶體中的Javascript資料物件,重新Bind在DetailView上,也就是說,DetailView可以直接取得由MasterView所Bind的物件,不用重新呼叫WCF取回。

但有個前題,如果DetailView要取得資訊細節比MasterView多出許多,那麼我們在一開始傳資料給MasterView時就把數十筆資料鉅細靡遺的細節(例如高達數十KB的訊息文字內容)都丟到前端存在記憶體中,便不是有效率的設計。此時,應該將取得清單與取得細節分成兩個函數,讓MasterView、DetailView各自呼叫對應的函數取回資料。在這個案例中,DetailView會顯示的內容不多,為了簡便,我們就直接採用{binding selectedData, source={{ master }}}的內建做法,如程式5。




如此,我們就實作出與先前UpdatePanel版相同效果的AJAX互動網頁,一樣進行更新時間、換頁與檢視產品明細的動作,再次觀察資料傳輸量。發現更新時間時上傳492 Bytes,下載242 Bytes,換頁時上傳531 Bytes下載1,757 Bytes。在檢視產品明細時,由於使用selectedData的做法直接讀取記憶體中的Javascript物件,未觸發任何瀏覽器與伺服器間的傳輸。(圖6)


圖6:Pure AJAX版的產品顯示。


最後,將UpdatePanel版與AJAX Templates版引發的傳輸結果作個比較,可驗證AJAX Templates確實大幅減少了資料傳輸量,但在程式的寫法上仍維持相當簡潔。(表1)


表1:UpdatePanel版與AJAX Templates版引發的傳輸結果



結語
UpdatePanel在開發簡便、低技術門檻背後付出可觀的傳輸效率代價,侷限了實際應用性,在ASP.NET 4.0中,則推出了ASP.NET AJAX Templates,以Javascript來回傳輸JSON格式並將產生介面的邏輯移至Client Side進行,降低伺服端的傳輸流量與運算負擔。在設計上,Binding語法也明顯簡化了以Javascript產生網頁元素的複雜度。最後透過實測比對,我們驗證了AJAX Templates較UpdatePanel大幅減少了資料傳輸量。相信在未來,Pure AJAX的概念將漸成動態網頁設計的主流。(完整程式碼請至www.runpc.com.tw下載)




【原文刊載於RUN!PC雜誌:2008年2月號】