TIPS-Invoke HttpRequest with ASP.NET AJAX client library
7 |
ASP.NET AJAX除了神奇地簡化了前端動態更新式網頁的開發工作化,還建立了不少Client-Side Script的基礎建設。神奇簡化的背後是靠複雜的ViewState、HTML部分更新堆砌起來的,ASP.NET AJAX所提供的UpdatePanel或ASP.NET 2.0的Script Callbacks,程式寫來超簡單,但每按一個鈕的代價是數十K資料在網路飛來飛(過陣子我會針對這部分做些探討),是否值得什麼東西都要AJAX化或放棄自己Coding HttpRequest改用ASP.NET AJAX? 非常值得商確。
基於以上的考量,我並不打算全部前端動態處理的東西都用UpdatePanel打死,除非是被呼叫的頻率不算高或以UpdatePanel可以讓程式簡化很多,有許多時候(尤其是得注意效能的場合),我還是會考慮採取HttpRequest Call另一隻ASPX程式的做法(連Web Service都不太想用,SOAP的Overhead也是挺可觀的)。不過,以前大家寫HttpRequest都是自己找Library、Code Sample,現在有了ASP.NET AJAX,理論上,就該借用它相關的Client-Side Function,避免各吹各的調。
以下示範,如何用ASP.NET AJAX的前端去Call另一隻ASPX傳回的XML:
function testXml() {
var wRequest = new Sys.Net.WebRequest();
//指定URL
wRequest.set_url("WebReqXml.aspx");
//非同步式呼叫,指定資料回傳的接收函數
wRequest.add_completed(xmlCallback);
//發射
wRequest.invoke();
}
function xmlCallback(executor, eventArgs) {
if(executor.get_responseAvailable())
{
//由Response中取出XML
var xd=executor.get_xml();
//用ASP.NET AJAX新推出的StringBuilder來接字串
var sb = new Sys.StringBuilder("User Info:");
sb.append("<br />Name="+xd.selectSingleNode("/Player/Name").text);
sb.append("<br />Skills="+xd.selectSingleNode("/Player/Skills").text);
//FireFox時,要用getElementById代替docuemnt.all,索性用$get較省事
$get("spnPlayerInfo").innerHTML=sb.toString();
}
else
{
if (executor.get_timedOut())
alert("Timed Out");
else if (executor.get_aborted())
alert("Aborted");
}
}
WebReqXml.aspx的寫法如下:
protected void Page_Load(object sender, EventArgs e)
{
XmlDocument xd = new XmlDocument();
xd.LoadXml("<Player></Player>");
XmlNode xn = xd.CreateElement("Name");
xn.InnerText = "Jeffrey";
xd.DocumentElement.AppendChild(xn);
xn = xd.CreateElement("Skills");
xn.InnerText = "Hoyucan";
xd.DocumentElement.AppendChild(xn);
Response.ContentType = "text/xml";
Response.Write(xd.OuterXml);
Response.End();
}
比較特別的地方都寫在註解裡了,只再補充三件事:
1) ASP.NET AJAX提供了$get, $addHandler這些Global Shortcuts函數,其實都只是很平常的找Element、設定Event之類的動作。有些人可能會懷疑直接寫document.all("...")不就得了,為什麼要大費周章只為了少打幾個字元? 你也許不知道,document.all("...")這種寫法遇到Firefox是會出局的。如果以跨瀏覽器為目標,使用這些捷徑函數,少打的可不只是幾個字而已,而是一大段依瀏覽器不同隨機應變的Code。
2) ASP.NET AJAX將Namespace的概念搬到Client端了。所以你會常看到Sys.Net.Blah... 這類的寫法。完整的Client Reference可以參考MS的官方參考文件。
3) 有些好東西已被MS在Client實作出來了,例如: StringBuilder。而Javascript base type extension強化了Array, Boolean, Date, Error, Number, Object及String物件,值得多多利用,有份很不錯的小抄可以參考。
除了以上傳統的XML式資料傳回法,這裡一定得提一下,ASP.NET AJAX引入的新概念---JSON(JavaScript Object Notation)!!
JSON有什麼神奇呢? 舉個例子來說,假設我們在.NET程式裡有個PlayerInfo物件(假設它有Name, Skills兩個Property),序列化成JSON字串後Response.Write回Client端,Client端可以把字串還原回後物件,接著在Javascript中一樣可以用player.Name, player.Skills去讀屬性值,酷吧?
先來看ASPX裡如何實作JSON的傳送端: 我們建立一個PlayerInfo Structure,直接將物件丟給System.Web.Script.Serialization.JavaScriptSerializer.Serialize(讓我想到變蠅人裡那台神奇的物質傳送器)後得到一個字串,將字串送給呼叫它的Javascript程式就完成了Server端的工作。
//一個簡單的玩家資料結構
public struct PlayerInfo
{
public string Name;
public string Skills;
public PlayerInfo(string name, string skills)
{
this.Name = name;
this.Skills = skills;
}
}
protected void Page_Load(object sender, EventArgs e)
{
PlayerInfo p = new PlayerInfo("Keroro", "Kero Ball");
System.Web.Script.Serialization.JavaScriptSerializer jss
= new System.Web.Script.Serialization.JavaScriptSerializer();
Response.Write(jss.Serialize(p));
Response.End();
}
Client端呼叫跟接收的程式跟處理XML差不多,我們用Sys.Serialization.JavaScriptSerializer.deserialize這個神奇函數,取代了原本的XMLDOM,就可以讓.NET Object在Javascript裡復活。
function testJson() {
var wRequest = new Sys.Net.WebRequest();
wRequest.set_url("WebReqJson.aspx");
wRequest.add_completed(jsonCallback);
wRequest.invoke();
}
function jsonCallback(executor, eventArgs) {
if(executor.get_responseAvailable())
{
//將其還原回Object, COOL!!
var player=
Sys.Serialization.JavaScriptSerializer.deserialize(
executor.get_responseData());
var sb = new Sys.StringBuilder("User Info:");
//可以直接引用Name屬性
sb.append("<br />Name="+player.Name);
sb.append("<br />Skills="+player.Skills);
$get("spnPlayerInfo").innerHTML=sb.toString();
}
else
{
if (executor.get_timedOut())
alert("Timed Out");
else if (executor.get_aborted())
alert("Aborted");
}
}
是不是很酷呀? 不過大家也別想太多,以為這樣就可以把SqlDataRreader傳到Javascript World把玩。JSON的目的主要是用來傳遞物件的資料結構,程式碼並不在其涵蓋範圍內。想要變成AJAX高手,還是乖乖學好JavaSript JavaScript(Update 2007-04-23 謝謝elleryq指正)吧!
Comments
# by 小熊子
在 javascript 端也實作了序列化的動作,讓寫 ajax 變得更方便
# by elleryq
"想要變成AJAX高手,還是乖乖學好JavaSript吧!" JavaScript??
# by Mn象
請問Mr.Dark thread : 小弟我是asp.net Ajax的新手,看了您這篇文章,我想照著試一遍,然而當我把原本沒有ajax功能的網頁加入 <script type="text/javascript" src="MicrosoftAjax.js"> </script> <script type="text/javascript" src="MicrosoftAjaxWebForms.js"> </script> 僅是如此,在IE執行就會出現錯誤訊息 : " Sys.ArgumentTypeException:Object of type 'Sys._Application' cannot be converted to type 'Sys._Application'. Parameter name: instance " (當然,因為我有把ie的debug功能打開) 不過,ajax功能依然可以正常執行,確實有收到來自另一個aspx檔的非同步訊息,可以用alert()印出來。 想請問上述的錯誤訊息該怎麼處理?
# by Jeffrey
to Mn象, 測了一下,沒遇到你發生的錯誤,也許是用的*.js版本不同緣故,也許可以把出錯的檔案打包讓大家下載試試。另外,如果只用HttpRequest,應該用不到MicrosoftAjaxWebForms.js才對。
# by Mn象
感恩 Mr.Dark ! 我是當天(20 February, 2009)去微軟下載的.js 我再試試看 ! 我是很嫩的新手,所以是胡亂把MicrosoftAjaxWebForms.js順便一起加進去的 :p 請問這樣留言是好的發問方式嗎,還是我應該要在什麼平台發問?
# by Maxi
黑暗大,有兩個問題 一,要用這些方便的function前,要去那裡include js lib嗎? 二,JSON可以把List<Structure>裡的Structures序列化傳到client side嗎? 這樣我就不用自己parse xml了 感謝
# by Jeffrey
to Maxi, 1) 文裡提到的$get, $addHandler來自ASP.NET AJAX提供的Client Script Library,比較簡單的方法是利用VS2005/2008的ASP.NET AJAX專案模版,從工具箱拖一個ScriptManager到ASP.NET網頁上就會自動include進來。 2) List<Structure>要轉成JSON格式應沒什麼問題,我常用到,比XML輕巧便捷多了。