先找個借口:好早就想分析下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" 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" 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方法產生的一序列動作我將在後文中繼續說明,有興趣的可以自己跟蹤下這些代碼的執行。