先找个借口

:好早就想分析下AjaxPro的代码实现机制了,一直苦于没时间,现在嘛总算有那么丁点了,开篇了,慢慢分析……
以一个最简单的例子开始:
点击一个客户端button,触发一个javascript函数,执行一个只有一个string参数的服务端方法,返回一个处理过的string,处理方法是将传入的string变成“Hi”+string +“!”;够简单了,为了是不希望罗嗦的代码影响简单的分析;
所有代码如下:
<%
@ Page Language="C#" AutoEventWireup="true" CodeFile="Test.aspx.cs" Inherits="Test"
%>

<!
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>

<
html
xmlns
="http://www.w3.org/1999/xhtml"
>
<
head
runat
="server"
>
<
title
>
无标题页
</
title
>

<
script
type
="text/javascript"
>
function doTest()

{
AJAXDemo.Examples.Test.TestMethod.GetTest("AjaxPro",doTest_callback);
}


function doTest_callback(res)
{
alert(res.value);
}
</
script
>
</
head
>
<
body
>
<
form
id
="form1"
runat
="server"
>
<
div
>
<
input
id
="Button1"
type
="button"
onclick
="doTest()"
value
="测试"
/></
div
>
</
form
>
</
body
>
</
html
>
Test.aspx.cs
public
partial
class
Test : System.Web.UI.Page

{
protected void Page_Load(object sender, EventArgs e)

{
Utility.RegisterTypeForAjax(typeof(AJAXDemo.Examples.Test.TestMethod));
}
}
AJAXDemo.Examples.Test
using
System;
using
AjaxPro;

namespace
AJAXDemo.Examples.Test

{
public class TestMethod

{
public TestMethod()

{}

[AjaxMethod]
public string GetTest(string testText)

{
return "Hi," + testText + "!";
}
}
}
1.首先我们看AjaxPro在页面上给我们生成了什么?
Test[1]
<!
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>

<
html
xmlns
="http://www.w3.org/1999/xhtml"
>
<
head
><
title
>
无标题页
</
title
>

<
script
type
="text/javascript"
>
function doTest()

{
AJAXDemo.Examples.Test.TestMethod.GetTest("AjaxPro",doTest_callback);
}


function doTest_callback(res)
{
alert(res.value);
}
</
script
>
</
head
>
<
body
>
<
form
name
="form1"
method
="post"
action
="Test.aspx"
id
="form1"
>
<
div
>
<
input
type
="hidden"
name
="__VIEWSTATE"
id
="__VIEWSTATE"
value
="/wEPDwUJNzgzNDMwNTMzZGRFekXifzWDNb+qFWPbJumdlZh/dQ=="
/>
</
div
>

<
script
type
="text/javascript"
src
="/AJAXDemo.2/ajaxpro/prototype.ashx"
></
script
>
<
script
type
="text/javascript"
src
="/AJAXDemo.2/ajaxpro/core.ashx"
></
script
>
<
script
type
="text/javascript"
src
="/AJAXDemo.2/ajaxpro/converter.ashx"
></
script
>
<
script
type
="text/javascript"
src
="/AJAXDemo.2/ajaxpro/AJAXDemo.Examples.Test.TestMethod,App_Code.un7rskvh.ashx"
></
script
>

<
div
>
<
input
id
="Button1"
type
="button"
onclick
="doTest()"
value
="测试"
/></
div
>
</
form
>
</
body
>
</
html
>
一定要注意这几行
<
script type
=
"
text/javascript
"
src
=
"
/AJAXDemo.2/ajaxpro/prototype.ashx
"
></
script
>
<
script type
=
"
text/javascript
"
src
=
"
/AJAXDemo.2/ajaxpro/core.ashx
"
></
script
>
<
script type
=
"
text/javascript
"
src
=
"
/AJAXDemo.2/ajaxpro/converter.ashx
"
></
script
>
<
script type
=
"
text/javascript
"
src
=
"
/AJAXDemo.2/ajaxpro/AJAXDemo.Examples.Test.TestMethod,App_Code.urx4hqkg.ashx
"
></
script
>
通过使用
http://localhost:3578/AJAXDemo.2/ajaxpro/prototype.ashx和
http://localhost:3578/AJAXDemo.2/ajaxpro/core.ashx不难发现,其中前面两个是源代码中带的两个js文件(core.js和prototype.js)转化出来的,基本内容也跟原来的文件一样,而converter.ashx和AJAXDemo.Examples.Test.TestMethod,App_Code.urx4hqkg.ashx里面有什么呢?看下面:
AJAXDemo.Examples.Test.TestMethod,App_Code.urx4hqkg.ashx
addNamespace(
"
AJAXDemo.Examples.Test
"
);
AJAXDemo.Examples.Test.TestMethod_class
=
Class.create();

AJAXDemo.Examples.Test.TestMethod_class.prototype
=
(
new
AjaxPro.AjaxClass()).extend(
{

GetTest: function(testText)
{

return this.invoke("GetTest",
{"testText":testText}, this.GetTest.getArguments().slice(1));
},

initialize: function()
{
this.url = '/AJAXDemo.2/ajaxpro/AJAXDemo.Examples.Test.TestMethod,App_Code.un7rskvh.ashx';
}
}
);
AJAXDemo.Examples.Test.TestMethod
=
new
AJAXDemo.Examples.Test.TestMethod_class();
converter.ashx
addNamespace(
"
Ajax.Web
"
);

Ajax.Web.NameValueCollection
=
function
()

{
this.__type = "System.Collections.Specialized.NameValueCollection";


this.add = function(key, value)
{

if(this[key] == null)
{
this[key] = value;
}
}

this.getKeys = function()
{
var keys = [];
for(key in this)
if(typeof this[key] != "function")
keys.push(key);
return keys;
}

this.getValue = function(key)
{
return this[key];
}

this.toJSON = function()
{
var o = this;
o.toJSON = null;
delete o.toJSON;
return AjaxPro.toJSON(o);
}
}




addNamespace(
"
Ajax.Web
"
);


Ajax.Web.DataTable
=
function
(columns, rows)
{

this.__type = "System.Data.DataTable, System.Data";
this.Columns = new Array();
this.Rows = new Array();


this.addColumn = function(name, type)
{
var c = new Object();
c.Name = name;
c.__type = type;
this.Columns.push(c);
}


this.toJSON = function()
{
var dt = new Object();

dt.Columns = [];
for(var i=0; i<this.Columns.length; i++)
dt.Columns.push([this.Columns[i].Name, this.Columns[i].__type]);

dt.Rows = [];

for(var i=0; i<this.Rows.length; i++)
{
var row = [];
for(var j=0; j<this.Columns.length; j++)
row.push(this.Rows[i][this.Columns[j].Name]);
dt.Rows.push(row);
}

return AjaxPro.toJSON(dt);
}


this.addRow = function(row)
{
this.Rows.push(row);
}


if(columns != null)
{

for(var i=0; i<columns.length; i++)
{
this.addColumn(columns[i][0], columns[i][1]);
}
}


if(rows != null)
{

for(var i=0; i<rows.length; i++)
{
var row = new Object();

for(var c=0; c<this.Columns.length && c<rows[i].length; c++)
{
row[this.Columns[c].Name] = rows[i][c];
}
this.addRow(row);
}
}
}


addNamespace(
"
Ajax.Web
"
);


Ajax.Web.DataSet
=
function
(tables)
{
this.__type = "System.Data.DataSet, System.Data";
this.Tables = new Array();


this.addTable = function(table)
{
this.Tables.push(table);
}


if(tables != null)
{

for(var i=0; i<tables.length; i++)
{
this.addTable(tables[i]);
}
}
}








function
Person(id)
{
this.FirstName = "";
this.FamilyName = "";
this.Age = 0;
this.ID = id;
this.__type = 'AJAXDemo.Examples.Classes.Person, App_Code.un7rskvh, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null';
}


Person.prototype.get_FullName
=
function
()
{
return this.FirstName + " " + this.FamilyName;
}


Person.prototype.toJSON
=
function
()
{
var o = new Object();

o.firstName = this.FirstName;
o.familyName = this.FamilyName;
o.age = this.Age;
o.id = this.ID;

return AjaxPro.toJSON(o);
}


Person.prototype.save
=
function
()
{
return Person.save(this);
}


Person.save
=
function
(p)
{
var ps = new PersonSaver();
return ps.savePerson(p); // synchronous call
}

var
PersonSaver
=
Class.create();

PersonSaver.prototype
=
(
new
AjaxPro.Request()).extend(
{

savePerson: function(p)
{

return this.invoke("SavePerson",
{"p":p}).value;
},

initialize: function()
{
this.url = "ajaxpro/AJAXDemo.Examples.Classes.Person, App_Code.un7rskvh, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null.ashx";
}
}
)


正因为是有了上面四个ashx文件我们的
function doTest()
{
AJAXDemo.Examples.Test.TestMethod.GetTest("AjaxPro",doTest_callback);
}
才得以异步执行,这些ashx文件又是怎么生成到页面上的,那得归功于web.config的相关配置和下面这句代码:
Utility.RegisterTypeForAjax(typeof(AJAXDemo.Examples.Test.TestMethod));
至于Utility.RegisterTypeForAjax方法产生的一序列动作我将在后文中继续说明,有兴趣的可以自己跟踪下这些代码的执行。
[未完待续]