天天看點

探讨微軟ASP.NET AJAX控件開發技術(伺服器端)

一、簡介

到目前為止,我們已經讨論了開發Ajax控件所涉及的用戶端相關技術。現在,讓我們來讨論此過程中與伺服器端相關的一些技術。

需要說明的是,在【用戶端】篇中我們的舉例本質上僅是使用ASP.NET AJAX架構提供的面向對象JavaScript技術來增強了一個用戶端圖像元件,而沒有明顯涉及到AJAX技術(除了ScriptManager在背景 以AJAX方式下載下傳并管理用戶端腳本代碼外)。是以,這個例子是簡單的,僅憑用戶端相關知識就可以使用這個增強控件。

但是,在實際開發中,當要增強的用戶端控件涉及到AJAX技術時,或者幹脆是想增強伺服器端元件(如UpdatePanel控件)時,我們必須進行 相關的伺服器端程式設計,而這要求我們必須對Ajax控件開發中所涉及的伺服器端相關聯的類有所了解。而且,還要以ASP.NET 2.0伺服器控件開發相關知識為基本前提,特别是在開發複雜的Ajax控件時。

在本篇中,我們要重新構造一個增強的圖像按鈕控件MySrvImageButton,此控件将以ASP.NET 2.0伺服器控件ImageButton為基礎。

二、AJAX控件開發伺服器端相關技術

首先,讓我們來看一下AJAX控件開發伺服器端相關元件及其關系,這些類之間的繼承關系圖如下圖1所示。

探讨微軟ASP.NET AJAX控件開發技術(伺服器端)

圖1:控件開發涉及的主要伺服器端類之間層次結構圖

上圖展示了元件、控件和擴充器之間的繼承關系。如你所見,為了開發一個控件(注意,Component和Extender不在本文讨論範圍之内), 我們有兩個選擇:其一,建立一個派生自ScriptControl的類;其二,建立一個實作IScriptControl接口的類。但是,如果你想使你的 控件從WebControl派生,那麼,ScriptControl應該是一個更好的選擇—因為它正是派生自WebControl控件本身。但是,如果你 想從頭開發建立你的控件,并且不要求實作WebControl所具備的任何内在特征,那麼,實作IScriptControl則更為恰當。此外,當你想在 一個現有控件(例如本文中的MySrvImageButton)中添加Ajax特征時選擇使用接口IScriptControl也會是你的選擇。但是這兩 種方法都要求重載下列兩個方法:①、GetScriptDescriptors;②、GetScriptReferences。

三、GetScriptDescriptors

這個方法負責在用戶端以自動方式生成$create語句(而在上篇中是使用手工方式)。它使用了一個特殊類ScriptDescriptor來生成它。在繼續往下讨論前,首先讓我們來浏覽一下ScriptDescriptor類中的繼承層次圖(如圖2所示):

探讨微軟ASP.NET AJAX控件開發技術(伺服器端)

圖2:ScriptDescriptor類中的繼承層次圖

顯然,每一種具體類型的元件都存在其單獨的描述符。如果你在開發一個正常元件,那麼,這個方法會傳回一個 ScriptComponentDescriptor的執行個體。對于擴充器而言,該方法傳回的是一個ScriptBehaviorDescriptor實 例;而對于一個控件,則傳回ScriptControlDescriptor類的執行個體。該描述符中提供了一些特定的方法用于建立伺服器端與用戶端的“連 接”。下面,還是讓我們來分析一個有關$Create語句是如何在伺服器端“注入”的簡短示例:

//上篇中從用戶端以手工方式使用$create

$create(AjaxImageButtonNamespace.MyCliImageButton,

{'hoverImageUrl':'Images/updateh.gif'},

{'click':buttonClicked}, null, $get('cliBtn'));

在本文中,我們在伺服器端以下列幾個語句共同自動生成$Create語句:

ScriptControlDescriptor desc =

new ScriptControlDescriptor("AjaxImageButtonLib.MySrvImageButton",

ClientID);

if (!string.IsNullOrEmpty(HoverImageUrl))

{

desc.AddProperty("hoverImageUrl", HoverImageUrl);

}

if (!string.IsNullOrEmpty(ClientClickFunction))

desc.AddEvent("click", ClientClickFunction);

return desc;

在上面的代碼中,我們在構造器中傳遞用戶端類型(盡管用戶端和伺服器端具有相同的類型名)和DOM元素ID。這一步将填充$Create語句的第一 個和最後一個參數。此後,我們設定hoverImageUrl屬性,它對應于$Create語句的屬性部分。最後,通過設定Click事件處理器,我們填 充$Create語句的事件部分。下面是腳本描述符中暴露的幾個重要的方法:

1)AddProperty()

這個方法能夠在用戶端添加一個屬性。第一個參數相應于屬性名,第二個參數對應該參數的取值。

2)AddEvent()

這個方法在用戶端添加一個事件。第一個參數相應于事件名,第二個參數對應你想綁定的函數的名稱。

3)AddScriptProperty()

這個方法能夠把JavaScript代碼指定為屬性的一個值。對于複雜的屬性指派通常都要求這樣的操作。

4)AddElementProperty()

這個方法在用戶端添加一個屬性,但是其與AddProperty方法間的差別在于,該值作為一個參數傳遞給$get方法。

5)AddComponentProperty()

這個方法負責在$Create語句的Component部分添加一個元件引用。該值将被用于$find語句中實作屬性的指派。這個方法的第一個參數相應于屬性名,第二個參數對應該元件的id。

四、GetScriptReferences

這個方法負責在ScriptManager中注冊JavaScript檔案。在這個方法中,針對每一個要求的JavaScript檔案,我們都需要建立一個相應的ScriptReference執行個體。例如,在圖像按鈕例子中,我們按如下方式注冊JavaScript檔案:

此外,我們還可以以嵌入式資源方式注冊JavaScript檔案。為此,我們必須首先在Visual Studio的解決方案資料總管中把一個JavaScript檔案标記為一種嵌入式資源。然後,我們必須添加上WebResource屬性以便利用 Asp.Net 2.0 Web資源處理器。下列代碼展示了如何把一個JavaScript檔案注冊為一個嵌入式資源:

[assembly: WebResource("MyControls.SubControl.Script1.js", "text/javascript")]

namespace MyControls{

public class SubControl: Control, IScriptControl

//………

IEnumerable<ScriptReference> IScriptControl.GetScriptReferences()

return new

ScriptReference(this.Page.ClientScript.GetWebResourceUrl(

this.GetType(), "MyControls.SubControl.Script1.js"));

此外,如果我們想實作IScriptControl接口而不是從ScriptControl中繼承的話,我們還必須重載OnPreRender與Render方法。這樣将能確定ScriptManger識别出該伺服器控件是一個支援Ajax功能的控件。

下列代碼展示了開發基于ASP.NET 2.0伺服器端控件的AJAX控件時必須在伺服器端實作的最少代碼:

using System;

using System.Collections.Generic;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

namespace DummyNamespace

public class DummyControl : Control, IScriptControl

public DummyControl(): base()

{}

protected override void OnPreRender(EventArgs e)

base.OnPreRender(e);

ScriptManager scriptManager = ScriptManager.GetCurrent(Page);

if (scriptManager == null)

throw new InvalidOperationException(

"此頁面中必須存在一個ScriptManager控件!");

scriptManager.RegisterScriptControl(this);

protected override void Render(HtmlTextWriter writer)

base.Render(writer);

writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);

writer.RenderBeginTag(HtmlTextWriterTag.Div);

writer.Write("這是一個啞元控件");

writer.RenderEndTag();

if (!DesignMode) {

ScriptManager.GetCurrent(this.Page).RegisterScriptDescriptors(this);

IEnumerable<ScriptDescriptor> IScriptControl.GetScriptDescriptors()

//因為這僅是一個啞元控件,是以我們隻是建立一個新的執行個體

return new ScriptControlDescriptor("DummyNamespace.DummyControl", ClientID);

return new ScriptReference(Page.ResolveUrl("~/DummyControl.js"));

上面代碼中,我們在OnPreRender方法中實作注冊控件,而在Render方法中注冊腳本描述符部分。當然,如果頁面上不存在 ScriptManager控件的話,我們必須抛出一個錯誤提示。但是,如果你正在開發非基于ASP.NETAJAX架構的控件的話,你完全可以從頁面中 删除ScriptManager控件。

五、建立基于ASP.NET伺服器端控件的增強AJAX圖像控件

(一)建立示例AJAX網站

啟動Visual Studio 2005,選擇“檔案→建立網站…”,然後選擇“ASP.NET AJAX-Enabled Web Site”模闆,命名工程為“AjaxServCtrlTest”,并選擇C#作為内置支援語言,最後點選“确定”。

(二)建立AJAX技術支援的增強伺服器控件

點選菜單“檔案→添加→建立項目…”,在“添加新項目”對話框中,從左邊選擇“項目類型”為“Visual C#→Windows”,從右邊選擇“模闆類型”為“Web控件庫”,輸入控件庫的名字為AjaxImageButtonLib,選擇目标目錄為前面建立 的網站根目錄,最後點選“确定”。

接下來,根據我們前面的分析,把類庫源WebCustomControl1.cs檔案的内容更改為以下形式:

//…………(省略命名空間引用部分)

namespace AjaxImageButtonLib

public class MySrvImageButton :

System.Web.UI.WebControls.ImageButton, IScriptControl

public string HoverImageUrl

get

object value = ViewState["hoverImageUrl"];

return (value == null) ? string.Empty : (string)value;

set

ViewState["hoverImageUrl"] = value;

public string ClientClickFunction

object value = ViewState["clientClickFunction"];

ViewState["clientClickFunction"] = value;

public MySrvImageButton()

: base()

throw new InvalidOperationException

("ScriptManager required on the page.");

if (!DesignMode)

new ScriptControlDescriptor("AjaxImageButtonLib.MySrvImageButton", ClientID);

yield return desc;

yield return new ScriptReference(Page.ResolveUrl("~/SrvImageButton.js"));

首先,我們注意到我們要建立的新控件MySrvImageButton繼承自ASP.NET伺服器控件ImageButton,并繼承了接口IScriptControl。

有了前面的理論描述,在此,我們省略對于其中幾個正常方法的描述。

接下來,我們要建構這個控件庫(即程式集)。右擊此庫工程,并點選“生成”指令以生成程式集AjaxImageButtonLib.dll,此庫檔案中即包含了我們的伺服器控件。

(三)建立用戶端JavaScript代碼

這裡建立的用戶端控件類相應的JavaScript檔案ImageButton.js在内容上完全相同,隻不過為了差別起見,我們進行了某些地方的重新命名罷了。在此不再贅述。

(四)在示例網頁中應用建構的新控件

以滑鼠右擊前面網站AjaxServCtrlTest,把它設定為“啟動項目”。事實上,因為這個網站工程與前面的類庫工程建立于同一個方案下,所 以,在前面生成程式集AjaxImageButtonLib.dll的一結束,建立的伺服器控件就被自動添加到Visual Studio 2005工具欄中,如下圖3所示。于是,我們可以直接把這個控件拖動到示例網頁Default.aspx中。

探讨微軟ASP.NET AJAX控件開發技術(伺服器端)

圖3:拖動建立的伺服器控件到示例網頁中

根據前面的控件代碼實作,不出所料,點選上圖3中的圖形按鈕控件,即可在其相應的“屬性”對話框中設定這個控件的hoverImageUrl屬性,而且指定其ClientClickFunction方法(其實正是此控件的click事件處理器函數指針)。

注意,因為控件代碼中的方法GetScriptReferences已經為我們自動生成了前面提到的$create方法,是以我們不需要再在ScriptManager中注冊在本篇中建立的JavaScript檔案—SrvImageButton.js了。

(五)運作及性能簡析

現在,請按F5鍵運作此頁面并移動滑鼠到圖像按鈕上觀察,你會注意到結果與上篇中的效果一緻(即在滑鼠移動切換新圖像時,這些動作都發生于客戶浏覽器端而不再與伺服器端相關)。下圖4相應于此示例頁面運作時刻快照。

探讨微軟ASP.NET AJAX控件開發技術(伺服器端)

圖4:示例網頁運作時刻螢幕快照

通過以滑鼠右擊網頁并選擇彈出菜單中的“檢視源檔案”觀察上、下篇中示例頁面相應的源碼,我們會注意到其内容基本是一緻的。另外,通過使用Fiddler觀察這兩個示例頁面下載下傳到用戶端時各子產品的大小,你也會注意到基本一緻,如下面圖5所示。

探讨微軟ASP.NET AJAX控件開發技術(伺服器端)

圖5:兩個示例頁面下載下傳到用戶端時各子產品大小比較

因為本文兩個例子極為簡單,是以其性能基本平衡。但随着服務端程式設計的複雜化,本篇中基于伺服器端控件的擴充方案應該有較大的性能損耗。但應該仍具有 令人滿意的效果,這也正是AJAX Control Toolkit控件數量急劇增加的重要原因之一。而上篇中的方案基于“純粹”(相對而言)的用戶端,即使性能上與本篇中方案相差無幾,但是卻明顯多出了跨 越伺服器端平台的優勢,這也正是上篇中方案吸引人的主要原因。

六、總結

雖然以上、下兩個篇幅形成此文,但是這也僅能通過簡短的例子向你闡述了開發ASP.NETAJAX架構中的Ajax控件所涉及的主要技術。盡管目前 的ASP.NET AJAX架構已經形成正規的1.0版本,而且這個架構為基于AJAX技術開發以ASP.NET 2.0為主的Web應用提供了全方位支援,但是這個架構仍然在許多方面有待改進。事實上,我們可以進一步沿着ASP.NET AJAX用戶端與伺服器端架構層次關系圖進一步擴充其底層。當然,在此架構與Visual Studio整合方面也存在相當的挖掘潛力。

如今,随着微軟Silverlight技術的推出,ASP.NET AJAX架構的重要性日顯突出。自然,與此架構相關的控件開發也必将在這一大環境中占居着重要的位置。

本文轉自朱先忠老師51CTO部落格,原文連結: http://blog.51cto.com/zhuxianzhong/59816,如需轉載請自行聯系原作者

繼續閱讀