DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> AJAX入門 >> AJAX詳解 >> 在ASP.NET中應用AJAX技術
在ASP.NET中應用AJAX技術
編輯:AJAX詳解     
Asynchronous JavaScript and XML(AJax)最近掀起的高潮,要完全歸功於Google在Google Suggest和Google Maps中的使用。對ASP.Net而言,Ajax不需要回傳就能進行服務器端處理,從而使客戶機(浏覽器)具有豐富的服務器端能力。換句話說,它為異步指派和處理請求與服務器響應提供了一個框架。Ajax利用了一些不是很新穎的已有技術,但是對這些技術(加到一起就是AJax)的愛好最近突然升溫。  

請嘗試Michael Schwarz的AJax .NET包裝器,通過它ASP.Net開發人員可以快速方便的部署很容易利用AJax功能的頁面。需要注意的是,這個包裝器處於初期開發階段,因此還沒有完全成熟。 

然而,AJAX這樣的技術很可能破壞分層體系結構(N-TIEr)。我的看法是,AJAX增加了表示邏輯層(甚至更糟,業務層)滲透到表示層的可能性。像我這樣嚴肅的架構師對這種想法可能畏步不前。我感到AJax的使用即便稍微越過了層次邊界,這種代價也是值得深思的。當然,這要視具體的項目和環境而定。 

起步:它是如何工作的——概述 

AJax依靠代理(broker)指派和處理往返服務器的請求。對此,.Net包裝器依靠客戶端XmlHttpRequest對象。多數浏覽器都支持XmlHttpRequest對象,這就是選擇它的原因。因為包裝器的目的是隱藏XMLHttpRequest的實現,我們就不再詳細討論它了。 

包裝器本身通過將.Net函數標記為AJAX方法來工作。標記之後,AJax就創建對應的Javascript函數,這些函數(和任何JavaScript函數一樣)作為代理可以在客戶端使用XMLHttpRequest調用。這些代理再映射回服務器端函數。 

復雜嗎?並不復雜。我們來看一個例子。假設有一個.Net函數: 

public int Add(int firstNumber, int secondNumber) 



return firstNumber + secondNumber; 



AJax .Net包裝器將自動創建名為“Add”、帶有兩個參數的Javascript函數。使用JavaScript(在客戶機上)調用該函數時,請求將傳遞給服務器並把結果返回給客戶機。 

初始設置 

我們首先介紹“安裝”項目中使用的.dll的步驟。如果您很清楚如何添加.dll文件引用,可以跳過這一節。 

首先,如果還沒有的話,請下載最新的AJAX版本。解壓下載的文件並把Ajax.dll放到項目的引用文件夾中。在Visual Studio.NET中有機Solution Explorer的“References(引用)”節點並選擇Add Reference(添加引用)。在打開的對話框中,單擊Browse(浏覽)並找到ref/Ajax.dll文件。依次單擊Open(打開)和Ok(確認)。這樣就可以用AJax .Net包裝器編程了。 

建立HttpHandler 

為了保證正常工作,第一步是在web.config中設置包裝器的HttpHandler。不需要詳細解釋HttpHandlers是什麼及其如何工作,只要知道它們用於處理ASP.Net請求就足夠了。比如,所有*.ASPx頁面請求都由System.Web.UI.PageHandlerFactory類處理。類似的,我們讓所有對Ajax/*.ashx的請求由AJax.PageHandlerFactory處理: 

<configuration> 

<system.web> 

<httpHandlers> 

<add verb="POST,GET" path="AJax/*.ashx" 

type="Ajax.PageHandlerFactory, AJax" /> 

</httpHandlers>   

... 

<system.web> 

</configuration> 

簡言之,上面的代碼告訴ASP.Net,和指定路徑(Ajax/*.ashx)匹配的任何請求都由Ajax.PageHandlerFactory而不是默認處理程序工廠來處理。不需要創建AJax子目錄,使用這個神秘的目錄只是為了讓其他HttpHandlers能夠在自己建立的子目錄中使用.ashx擴展。 

建立頁面 

現在我們可以開始編碼了。創建一個新頁面或者打開已有的頁面,在file後的代碼中,為Page_Load事件添加以下代碼: 

public class Index : System.Web.UI.Page{ 

private void Page_Load(object sender, EventArgs e){ 

Ajax.Utility.RegisterTypeForAJax(typeof(Index));       

//...     



//...   



調用RegisterTypeForAJax將在頁面上引發後面的JavaScript(或者在頁面中手工加入以下兩行代碼): 

<script language="Javascript" src="AJax/common.ashx"></script> 

<script language="Javascript"  

src="AJax/Namespace.PageClass,AssemblyName.ashx"></script>   

其中最後一行的含義是: 

Namespace.PageClass——當前頁面的名稱空間和類(通常是@Page指令中Inherits屬性的值) 

AssemblyName——當前頁面所屬程序集的名稱(通常就是項目名) 

下面是AJaxPlay項目中sample.ASPx頁面的結果例子: 

<%@ Page Inherits="AJaxPlay.Sample" Codebehind="sample.ASPx.cs" ... %> 

<Html> 

<head> 

<script language="Javascript" src="AJax/common.ashx"></script> 

<script language="Javascript" 

src="Ajax/AjaxPlay.Sample,AJaxPlay.ashx"></script> 

</head> 

<body>     

<form id="Form1" method="post" runat="server"> 

... 

</form>     

</body> 

</Html> 

可以在浏覽器中手工導航到src路徑(查看源代碼,復制粘貼路徑)檢查是否一切正常。如果兩個路徑都輸出一些(似乎)毫無意義的文本,就萬事大吉了。如果什麼也沒輸出或者出現ASP.Net錯誤,則表明有些地方出現問題。 

即便不知道HttpHandlers如何工作,上面的例子也很容易理解。通過web.config,我們已經保證所有對AJax/*.ashx的請求都由自定義的處理程序處理。顯然,這裡的兩個腳本標簽將由自定義的處理程序處理。 

創建服務器端函數  

現在來創建可從客戶端調用中異步訪問的服務器端函數。因為目前還不支持所有的返回類型(不用擔心,將在目前的基礎上開發新的版本),我們繼續使用簡單的ServerSideAdd函數吧。在file後的代碼中,向頁面添加下列代碼: 

[Ajax.AJaxMethod()] 

public int ServerSideAdd(int firstNumber, int secondNumber) 



return firstNumber + secondNumber; 



要注意,這些函數具有Ajax.AJaxMethod屬性集。該屬性告訴包裝器這些方法創建JavaScript代理,以便在客戶端調用。 

客戶端調用 

最後一步是用Javascript調用該函數。AJax包裝器負責創建帶有兩個參數的JavaScript函數Sample.ServerSideAdd。對這種最簡單的函數,只需要調用該方法並傳遞兩個數字: 

<%@ Page Inherits="AJaxPlay.Sample" Codebehind="sample.ASPx.cs" ... %> 

<Html> 

<head> 

<script language="Javascript" src="AJax/common.ashx"></script> 

<script language="Javascript"  

src="Ajax/AjaxPlay.Sample,AJaxPlay.ashx"></script> 

</head> 

<body>     

<form id="Form1" method="post" runat="server"> 

<script language="Javascript"> 

var response = Sample.ServerSideAdd(100,99); 

alert(response.value); 

</script> 

</form>     

</body> 

</Html> 

當然,我們不希望僅僅用這種強大的能力來警告用戶。這就是所有客戶端代理(如JavaScript Sample.ServerSideAd函數)還接受其他特性的原因。這種特性就是為了處理響應而調用的回調函數: 

Sample.ServerSideAdd(100,99, ServerSideAdd_CallBack); 

function ServerSideAdd_CallBack(response){ 

if (response.error != null){ 

alert(response.error); 

return; 



alert(response.value); 



從上述代碼中可以看到我們指定了另外一個參數。ServerSideAdd_CallBack(同樣參見上述代碼)是用於處理服務器響應的客戶端函數。這個回調函數接收一個響應對象,該對象公開了三個主要性質 

Value——服務器端函數實際返回的值(無論是字符串、自定義對象還是數據集)。 

Error——錯誤消息,如果有的話。 

Request——XML http請求的原始響應。 

Context——上下文對象。 

首先我們檢查error只看看是否出現了錯誤。通過在服務器端函數中拋出異常,可以很容易處理error特性。在這個簡化的例子中,然後用這個值警告用戶。Request特性可用於獲得更多信息。 

處理類型  

返回復雜類型 

AJax包裝器不僅能處理ServerSideAdd函數所返回的整數。它目前還支持integers、strings、double、booleans、DateTime、DataSets和DataTables,以及自定義類和數組等基本類型。其他所有類型都返回它們的ToString值。 

返回的DataSets和真正的.Net DataSet差不多。假設一個服務器端函數返回DataSet,我們可以通過下面的代碼在客戶端顯示其中的內容: 

<script language="JavaScript"> 

//Asynchronous call to the mythical "GetDataSet" server-side function 

function getDataSet(){ 

AJaxFunctions.GetDataSet(GetDataSet_callback);     



function GetDataSet_callback(response){ 

var ds = response.value; 

if(ds != null && typeof(ds) == "object" && ds.Tables != null){ 

var s = new Array(); 

s[s.length] = "<table border=1>"; 

for(var i=0; i<ds.Tables[0].Rows.length; i++){ 

s[s.length] = "<tr>"; 

s[s.length] = "<td>" + ds.Tables[0].Rows[i].FirstName + "</td>"; 

s[s.length] = "<td>" + ds.Tables[0].Rows[i].Birthday + "</td>"; 

s[s.length] = "</tr>"; 



s[s.length] = "</table>"; 

tableDisplay.innerHtml = s.join(""); 



else {  

alert("Error. [3001] " + response.request.responseText);  





</script> 

AJax還可以返回自定義類,唯一的要求是必須用Serializable屬性標記。假設有如下的類: 

[Serializable()] 

public class User{ 

private int _userId; 

private string _firstName; 

private string _lastName; 

  public int userId{ 

get { return _userId; } 



public string FirstName{ 

get { return _firstName; } 



public string LastName{ 

get { return _lastName; } 



public User(int _userId, string _firstName, string _lastName){ 

this._userId = _userId; 

this._firstName = _firstName; 

this._lastName = _lastName; 



public User(){} 

[AJaxMethod()] 

public static User GetUser(int userId){ 

//Replace this with a DB hit or something :) 

return new User(userId,"Michael", "Schwarz"); 





我們可以通過調用RegisterTypeForAJax注冊GetUser代理: 

private void Page_Load(object sender, EventArgs e){ 

Utility.RegisterTypeForAJax(typeof(User)); 



這樣就可以在客戶端異步調用GetUser: 

<script language="Javascript"> 

function getUser(userId){ 

User.GetUser(GetUser_callback); 



function GetUser_callback(response){ 

if (response != null && response.value != null){ 

var user = response.value; 

if (typeof(user) == "object"){           

alert(user.FirstName + " " + user.LastName); 







getUser(1); 

</script> 

響應中返回的值實際上是一個對象,公開了和服務器端對象相同的屬性(FirstName、LastName和UserId)。 

自定義轉換器  

我們已經看到,Ajax .NET包裝器能夠處理很多不同的.NET類型。但是除了大量.NET類和內建類型以外,包裝器對不能正確返回的其他類型僅僅調用ToString()。為了避免這種情況,AJax .Net包裝器允許開發人員創建對象轉換器,用於在服務器和客戶機之間平滑傳遞復雜對象。 

其他事項 

在其他類中注冊函數 

上面的例子中,我們的服務器端函數都放在執行頁面背後的代碼中。但是,沒有理由不能把這些函數放在單獨的類文件中。要記住,包裝器的工作方式是在指定類中發現所有帶Ajax.AjaxMethod的方法。需要的類通過第二個腳本標簽指定。使用Ajax.Utility.RegisterTypeForAJax,我們可以指定需要的任何類。比如,將我們的服務器端函數作為單獨的類是合情合理的: 

Public Class AJaxFunctions 

<Ajax.AJaxMethod()> _ 

Public Function Validate(username As String, passWord As String) As Boolean 

’do something 

’Return something 

End Function 

End Class 

通過指定類的類型而不是頁面就可以讓AJax包裝器創建代理: 

private void Page_Load(object sender, EventArgs e){ 

Ajax.Utility.RegisterTypeForAjax(typeof(AJaxFunctions)); 

//... 



要記住,客戶端代理的名稱是<ClassName>.<ServerSideFunctionName>。因此,如果ServerSideAdd函數放在上面虛構的AjaxFunctions類中,客戶端調用就應該是: AJaxFunctions.ServerSideAdd(1,2)。 

代理到底是如何工作的 

Ajax工具生成的第二個腳本標簽(也可以手工插入)傳遞了頁面的名稱空間、類名和程序集。根據這些信息,Ajax.PageHandlerFactory就能夠使用反射得到具有特定屬性的任何函數的詳細信息。顯然,處理函數查找具有AjaxMethod屬性的函數並得到它們的簽名(返回類型、名稱和參數),從能夠創建必要的客戶端代理。具體而言,包裝器創建一個和類同名的Javascript對象,該對象提供代理。換句話說,給定一個帶有Ajax ServerSideAdd方法的服務器端類AjaxFunctions,我們就會得到公開ServerSideAdd函數的AJaxFunction JavaScript對象。如果將浏覽器指向第二個腳本標簽的路徑就會看到這種動作。 

返回Unicode字符 

AJax .Net包裝器能夠從服務器向客戶機返回Unicode字符。為此,數據在返回之前必須在服務器上用Html編碼。比如: 

[Ajax.AJaxMethod] 

public string Test1(string name, string email, string comment){ 

string Html = ""; 

Html += "Hello " + name + "<br>"; 

Html += "Thank you for your comment <b>"; 

html += System.Web.HttpUtility.HtmlEncode(comment); 

Html += "</b>."; 

return Html; 

}

SessionState  

服務器端函數中很可能需要訪問會話信息。為此,只需要通過傳遞給Ajax.AjaxMethod屬性的一個參數告訴AJax啟用這種功能。 

在考察包裝器會話能力的同時,我們來看看其他幾個特性。這個例子中我們有一個文檔管理系統,用戶編輯的時候會對文檔加鎖。其他用戶可以請求在文檔可用的時候得到通知。如果沒有AJAX,我們就只能等待該用戶再次返回來檢查請求的文檔是否可用。顯然不夠理想。使用支持會話狀態的AJax就非常簡單了。 

首先來編寫服務器端函數,目標是循環遍歷用戶希望編輯的documentId(保存在會話中)並返回所有已釋放的文檔。 

[Ajax.AJaxMethod(HttpSessionStateRequirement.Read)] 

public ArrayList DocumentReleased(){ 

if (HttpContext.Current.Session["DocumentsWaiting"] == null){ 

return null; 



ArrayList readyDocuments = new ArrayList(); 

int[] documents = (int[])HttpContext.Current.Session["DocumentsWaiting"]; 

for (int i = 0; i < documents.Length; ++i){ 

Document document = Document.GetDocumentById(documents[i]); 

if (document != null && document.Status == DocumentStatus.Ready){ 

readyDocuments.Add(document); 

}         



return readyDocuments; 





要注意,我們指定了HttpSessionStateRequirement.Read值(還可以用Write和ReadWrite)。 

現在編寫使用該方法的Javascript

<script language="Javascript"> 

function DocumentsReady_CallBack(response){ 

if (response.error != null){ 

alert(response.error); 

return; 



if (response.value != null && response.value.length > 0){ 

var div = document.getElementById("status"); 

div.innerHtml = "The following documents are ready!<br />"; 

for (var i = 0; i < response.value.length; ++i){ 

div.innerHtml += "<a href=\"edit.ASPx?documentId=" + response.value[i].DocumentId + "\">" + response.value[i].Name + "</a><br />"; 

}       



setTimeout(’page.DocumentReleased(DocumentsReady_CallBack)’, 10000); 



</script>   

<body > 

我們的服務器端函數在頁面加載時調用一次,然後每隔10秒鐘調用一次。回調函數檢查響應看看是否有返回值,有的話則在div標簽中顯示該用戶可使用的新文檔。 

結束語 

AJAX技術已經催生了原來只有桌面開發才具備的健壯而豐富的Web界面。Ajax .NET包裝器讓您很容易就能利用這種新的強大技術。請注意,AJax .Net包裝器和文檔仍在開發之中。 
XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved