上面这段代码的粗体部分
NAMESPACE.PAGECLASS,ASSEMBLYNAME含义如下:
NAMESPACE.PAGECLASS当前页面的命名空间和类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 path(通过查看源文件并copy)打开,一切都能正常的工作。如果输出了无意义的文本表示到目前为止是正确的,如果输出asp.net错误,则表示中间出现了错误。 即使你不了解HttpHandle的工作方式,也应该可以理解上面的描述。通过web.config,我们可以确保发送向ajax/*.ashx的请求由我们自定义的句柄来处理,很显然,两个脚本标记由自定义句柄处理。 编写服务端函数 现在我们编写服务器端函数,他们可以被客户端异步的调用。尽管现在还不能支持全部的返回类型,我们仍坚持服务器端添加功能。在codebehind文件的页面类里,添加下面的方法: 'VB.Net<Ajax.AjaxMethod()> _Public Function ServerSideAdd (byval firstNumber As Integer, byval secondNumber As Integer) As IntegerReturn firstNumber + secondNumberEnd Function //C#[Ajax.AjaxMethod()]public int ServerSideAdd(int firstNumber, int secondNumber){ return firstNumber + secondNumber;} 注意,这个函数有Ajax.AjaxMethod()定制属性,属性服务会告知ajax封装类为此方法创建一个javascript代理,这样才能被客户端调用。 定制客户端调用 接下来在客户端用javascript调用函数。Ajax封装类会创建一个javascript函数,带有两个参数,名字是 类名.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> 当然,我们不能把这么强大的功能仅仅用来通过alert来提醒浏览者,这就是为什么所有的客户端代理(如 类名.ServerSideAdd函数)同时带有一个额外的定制属性。这个属性是用来处理服务器响应的回调函数: Sample.ServerSideAdd(100,99, ServerSideAdd_CallBack);function ServerSideAdd_CallBack(response){ if (response.error != null){ alert(response.error); return; } alert(response.value);} 从上面的代码中可以看出,我们为ServerSideAdd函数增加了一个额外参数ServerSideAdd_CallBack,这个参数就是用来处理服务器端响应的客户端函数。这个callback函数接受一个带有四个关键属性的response对象: value服务器端函数执行的返回值(可能是一个字符串、自定义对象或者dataset)error如果发生错误,则返回错误信息.request原始的xmlHttpRequest请求context一个上下文对象 我们首先应该检查是否有错误发生,你可以通过在服务器端函数抛出异常来实现这个error属性。在上面这个例子中,我们简单的alert了一个值,就是value属性;request属性可以用来取得额外的信息(见下面的表格)如果你想了解更多的关于XmlHttpRequest的知识,可以查看下面的链接: http://www.quirksmode.org/blog/archives/2005/02/xmlhttp_linkdum.html 处理类型 返回一个复杂类型 Ajax可以支持除了我们上面ServerSideAdd函数返回的Int值以外很多类型。他可以直接支持integers, strings, double, booleans, DateTime, DataSets 和 DataTables,也支持简单的自定义类型和数组。其他的类型通过其ToString方式来返回字符串。 返回DataSet的工作就像真正的.net Dataset.给出一个返回DataSet的服务器端函数,我们可以通过下面的方法在客户端显示: <script language="JavaScript">//Asynchronous call to the mythical "GetDataSet" server-side functionfunction 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()]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 and UserId)。 译者注:其他的类型只能由开发者通过在服务器端函数在返回值时自定义转换为ajax支持的类型来实现了,ajax推荐使用ToString方法。 其他工作方式 在其他类注册函数 在上面的例子及描述中,我们都是通过在页面的codebehind文件里完成函数的注册,但并不是说只能在页面的codebehide文件里完成注册,我们也可以在其他类中注册函数。回忆一下,Ajax封装类是通过在特定类里面查找那些有Ajax.AjaxMethod()属性的方法来完成工作的,这些类在客户端又通过两个script片断来完成返回值描述。使用Ajax.Utility.RegisterTypeForAjax,我们可以得到任何我们想得到类的详细内容。例如,下面的例子可以说明我们在其他类中使用服务器端函数是合法的:
Public Class AjaxFunctions<Ajax.AjaxMethod()> _Public Function Validate(username As String, password As String) As Boolean'do something'Return somethingEnd FunctionEnd Class 不过我们需要首先在调用页面注册这个代理类,类的名字不再是页面类,而是我们使用的这个类: 'Vb.NetPrivate Sub Page_Load(sender As Object, e As EventArgs) Handles MyBase.LoadAjax.Utility.RegisterTypeForAjax(GetType(AjaxFunctions))'...End Sub //C#private void Page_Load(object sender, EventArgs e){Ajax.Utility.RegisterTypeForAjax(typeof(AjaxFunctions));//...} 记住,客户端调用使用这种格式的名字<ClassName>.<ServerSideFunctionName>。因此,如果上面的Serversideadd函数位于AjaxFunctions类,而不是页面类的话,客户端调用则变为:AjaxFunctions.ServerSideAdd(1,2) 代理是怎样工作的呢? 第二个script标签,如下面的示例<script type="text/javascript" src="/cqyd/ajax/cqyd.SchemeSendWatch,cqyd.ashx"></script> 是由Ajax utility通过命名空间、类以及页面程序集自动生成的(当然也可以人工加入),从这一点我们可以想到Ajax.PageHandlerFactory是通过反射来取得有定制属性的函数的细节。很显然,Handler寻找带有AjaxMethod定制属性的函数,取得他们的特征(返回类型、名称、参数)并依据这些信息创建客户端代理。特别的,ajax创建一个与类型相同的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;}
在服务端函数,你可能需要接受传送的session信息,为了做到这一点,必须要在想实现这个方式的服务端函数的Ajax.AjaxMethod属性上传递一个参数。 在查看ajax可以支持session的时候,我们先看看其他的特征。在下面这个例子中,我们有一个文档管理系统,当一个用户对文档进行编辑的时候会给这个文档加锁,其他用户需要等到这个文档可用时才能修改。不使用Ajax,用户需要不断等待刷新,因为不得不不断的去检查文档的状态是否为可用,这当然不是一个很好的方案。用ajax的session state支持,这就比较容易了。 我们首先写一个函数,这个函数通过遍历文档ID找到用户需要的文档,存储到session里,并返回没有占用的文档:
'Vb.Net<Ajax.AjaxMethod(HttpSessionStateRequirement.Read)> _Public Function DocumentReleased() As ArrayListIf HttpContext.Current.Session("DocumentsWaiting") Is Nothing ThenReturn NothingEnd IfDim readyDocuments As New ArrayListDim documents() As Integer = CType(HttpContext.Current.Session("DocumentsWaiting"), Integer())For i As Integer = 0 To documents.Length - 1Dim document As Document = document.GetDocumentById(documents(i))If Not document Is Nothing AndAlso document.Status = DocumentStatus.Ready ThenreadyDocuments.Add(document)End IfNextReturn readyDocumentsEnd Function
//C#[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 and 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 οnlοad="setTimeout('Document.DocumentReleased(DocumentsReady_CallBack)', 10000);"> 页面加载后每10秒钟向服务器函数请求一次。如果有返回,则call back函数检查response,并把最新的结果显示出来。 结论 Ajax技术可以给客户端提供丰富的客户体验,而ajax.net为您容易的实现这样强大的功能提供了可能。