上次写到Ajax.NET库中最为重要的一个类:AjaxRequestProcessor,所有的Ajax请求都是通过该类来处理.该类中只有一个方法,public void Run() ,应该说理解了这个方法,Ajax.NET框架的工作原理就差不多明白了,我是这么想的.我想通过注释的方式来解读这个方法.
public
void
Run()
...
{
//检查当前上下文是否启用了ASP.NET跟踪功能.如果启用了就输出一条跟踪信息.启用跟踪功能可以方便调试.
//如果要启用该功能可以在页面上的Page指令中加Trace,如<%@ Page Trace="true" %>,这样就可以在访问页面时
//看到很多额外的信息.
if ( context.Trace.IsEnabled )

...{
context.Trace.Write( "Ajax.NET", "Begin ProcessRequest" );
}

DateTime now = DateTime.Now;

//得到当前请求的文件名.
string typeName = Path.GetFileNameWithoutExtension( context.Request.FilePath );


if ( Utility.Settings != null && Utility.Settings.UrlNamespaceMappings.Contains( typeName ) ) ...{
typeName = Utility.Settings.UrlNamespaceMappings[ typeName ].ToString();
}

//初始化AjaxProcessor类,该类是一个帮助类.主要功能是输出客户端脚本.下面马上就能看到.
AjaxProcessor ajaxer = new AjaxProcessor();
ajaxer.InitializeContext( ref context );

// return the common scripts for this type of processor
// 为该处理类返回通用脚本
//如果该请求的文件名为common,就是专门为了处理页面中的这一行<script language="javascript" src="ajax/common.ashx">

if ( typeName.ToLower() == "common" ) ...{

if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "Render common Javascript" );
}

//该脚本缓存1分钟,类型为纯文本.
context.Response.Expires = 1;
context.Response.ContentType = "text/plain";


/**//*
* 调用AjaxProcessor类中的方法RenderCommonScript,目的是输出ajax.js或ajax_mobile.js这个用于
* 包装和处理由XMLHttpRequest对象生成的Ajax请求.
internal void RenderCommonScript() {
string commonAjax = "ajax.js";

if ( context.Request.UserAgent.IndexOf( "Windows CE; PPC;" ) >= 0 ) {
commonAjax = "ajax_mobile.js"; //该文件用于移动设备.
}
//因为这两个脚本文件已经作为资源编译到程序集中,所以可以用下面的方式直接从程序集中读取.
StreamReader sr = new StreamReader( Assembly.GetCallingAssembly().GetManifestResourceStream( "Ajax." + commonAjax ) );
//Write也是AjaxProcessor类中的帮助方法,其实就是Response.Write方法的封装.
Write( sr.ReadToEnd() );
sr.Close();
//客户端脚本的版本号
Write( "var ajaxVersion = '5.7.22.2';" );
}
*/
ajaxer.RenderCommonScript();


if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "End ProcessRequest" );
}

//如果是请求通用脚本,那任务已经完成,下面的代码就不用再执行了.返回停止Response.
return;
}

//如果不是请求通用脚本,那就是具体的请求.所以不应该缓存.
context.Response.Expires = 0;
context.Response.AddHeader( "cache-control", "no-cache" );

//定义一些变量,为反射做准备.
Type type;
MethodInfo[] mi = null;
string methodName = null;

object[] po = new object[] ...{};

//这里的typeName的格式是这样的:"NameSapce.Class,Assembly",Type的GetType方法可以接受该参数
//动态取得该类的引用.这是反射的第一步.
type = Type.GetType( typeName );
mi = type.GetMethods(); //读取该类中的所有方法,并保存.
//调用AjaxProcessor类中的GetMethodName方法,就是读取要调用的方法名称.
//该方法名称作为请求的一个参数传递给服务器.类似于这样:http://xxx/xx.ashx?_method=MethodName
//该方法就是读取这里的MethodName.这是反射的第二步,读取要调用的方法.
methodName = ajaxer.GetMethodName();

string md5 = null;
StreamReader sr = null;
//尝试从Cache中读取是否是一模一样的请求,如果是一样的那么返回的值也是一样的,那就节省了调用方法以及处理参数等的开销.
byte[] b = new byte[context.Request.ContentLength];

if ( context.Request.HttpMethod == "POST" && context.Request.InputStream.Read( b, 0, b.Length ) >= 0 ) ...{
md5 = MD5Helper.GetHash( b );
sr = new StreamReader( new MemoryStream( b ), UTF8Encoding.UTF8 );


if ( context.Cache[ type.FullName + "|" + md5 ] != null ) ...{
context.Response.Write( context.Cache[ type.FullName + "|" + md5 ].ToString() );
// context.Response.Write(""" + md5 + DateTime.Now + """);


if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "End ProcessRequest" );
}
return;
}
}

//如果请求要调用的方法有AjaxMethodAttribute自定义属性.
//则检查该自定义属性并尝试调用该方法.只有添加该属性的方法才能被调用.

if ( methodName != null ) ...{
MethodInfo method = type.GetMethod( methodName );//取得该方法


if ( method != null ) ...{
//尝试读取AjaxmethodAttribute自定义属性.
object[] ii = method.GetCustomAttributes( typeof (AjaxMethodAttribute), true );


if ( ii.Length != 1 ) ...{
// 要调用的方法没有AjaxMethodAttribute自定义属性的话,产生一个异常.
//HandleException也是AjaxProcessor中的一个方法.功能是输出异常信息.以XML文件的形式或者文本形式.
ajaxer.HandleException( new NotImplementedException( "The method '" + context.Request[ "m" ] + "' is not implemented or access refused." ), null );

if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "End ProcessRequest" );
}
//产生异常后直接返回.
return;
}

// 设置方法参数.
//先取得要调用的服务器端的方法的参数列表.
ParameterInfo[] para = method.GetParameters();
po = new object[para.Length];


try ...{
//这也是AjaxProcessor类的帮助方法,功能是从传递过去的StreamSeader,sr中或直接从Request URL中读取参数并把值设置到po中.
//该方法的详细说明见AjaxProecssor类的注释.
ajaxer.RetreiveParameters( ref sr, para, ref po );


} catch ( Exception ex ) ...{
ajaxer.HandleException( ex, "Could not retreive parameters from HTTP request." );
}

// 尝试调用方法.
object o = null;


try ...{

if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "Invoking " + type.FullName + "." + method.Name );
}

//如果这是个静态方法,我们就不用再实例化该类.一些类没有默认构选器.

if ( method.IsStatic ) ...{

try ...{
//用反射的方式调用某方法.这是反射的第三步.调用方法.
o = type.InvokeMember(
methodName,
BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.IgnoreCase,
null, null, po );

} catch ( Exception ex ) ...{ //catch中的都是异常处理.如果出现异常,报告异常.

if ( ex.InnerException != null ) ...{
ajaxer.HandleException( ex.InnerException, null );

} else ...{
ajaxer.HandleException( ex, null );
}


if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "End ProcessRequest" );
}
//有异常发生就返回.
return;
}

} else ...{
// Create an instance of the class using the default constructor that will
// not need any argument. This can be a problem, but currently I have no
// idea on how to specify arguments for the constructor.
//如果不是静态方法.则用默认无参构造器新建一个该类的实例.这可能是个问题,但是现在我想不出办法
//如何去设置构造器的参数.

try ...{

object c = (object) Activator.CreateInstance( Type.GetType( typeName ), new object[] ...{} );


if ( c != null ) ...{
o = method.Invoke( c, po );
}

} catch ( Exception ex ) ...{

if ( ex.InnerException != null ) ...{
ajaxer.HandleException( ex.InnerException, null );

} else ...{
ajaxer.HandleException( ex, null );
}


if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "End ProcessRequest" );
}

return;
}
}

} catch ( Exception ex ) ...{

if ( ex.InnerException != null ) ...{
ajaxer.HandleException( ex.InnerException, null );

} else ...{
ajaxer.HandleException( ex, null );
}


if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "End ProcessRequest" );
}
//如果调用方法过程出现异常,返回,不再执行下面的代码.
return;
}

// 在客户端我们想要一个真实的对象.
// JSON 可以由两种方式构造
// - 一个名/值对集合.在各种不同的语言中这可以被理解为对象,记录,结构,字典,散列表等
// - 一个排序的值列表.在大多数语言中,这被认为是数组.

if ( !Utility.ConverterRegistered ) ...{
Utility.RegisterConverterForAjax( null );
}


try ...{
//如果返回的值是 XmlDocument 我们不进行转换直接返回.
//在客户端我们可以用 .responseXML或 .xml 来读取.

if ( o != null && o.GetType() == typeof (XmlDocument) ) ...{

//设置响应类型,并输出到响应流中.
context.Response.ContentType = "text/xml";
( (XmlDocument) o ).Save( context.Response.OutputStream );


if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "End ProcessRequest" );
}

return;
}

//尝试把返回的值,转换成JSON格式的StringBuilder对象.
StringBuilder sb = new StringBuilder();


try ...{
DefaultConverter.ToJSON( ref sb, o );

} catch ( StackOverflowException stack ) ...{
ajaxer.HandleException( stack, "The class you are returning is not supported." );
return;

} catch ( Exception ex ) ...{
ajaxer.HandleException( ex, "AjaxRequestProcessor throw exception while running ToJSON" );
return;
}


if ( context.Request[ "_return" ] != null && context.Request[ "_return" ] == "xml" ) ...{
// 如果是掌上电脑,我们每次都返回xml,应该掌上电脑不支持XMLHttpRequest
//context.Response.ContentType = "text/xml";
XmlDocument doc = new XmlDocument();
doc.LoadXml( "<Ajax/>" );

doc.DocumentElement.InnerText = sb.ToString();

doc.Save( context.Response.OutputStream );

} else ...{

if ( md5 != null ) ...{
object[] ma = method.GetCustomAttributes( typeof (AjaxMethodAttribute), true );

if ( ma.Length == 0 ) ...{} else ...{
AjaxMethodAttribute m = (AjaxMethodAttribute) ma[ 0 ];

if ( m.IsCacheEnabled ) ...{
context.Cache.Add( type.FullName + "|" + md5, sb.ToString(), null, now.AddSeconds( m.CacheDuration.TotalSeconds ), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null );
}
}
}

// 直接响应 JSON 对象.


if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "JSON string: " + sb.ToString() );
}
context.Response.Write( sb.ToString() );
}


if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "End ProcessRequest" );
}

return;

} catch ( Exception ex ) ...{
ajaxer.HandleException( ex, "Error while converting object to JSON." );

if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "End ProcessRequest" );
}

return;
}
}

// 如果代码能执行到这里,表示方法没有被实现或没有AjaxMethodAttribute自定义属性.
ajaxer.HandleException( new NotImplementedException( "The method '" + context.Request[ "m" ] + "' is not implemented or access refused." ), null );

if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "End ProcessRequest" );
}

return;
}

// 如果没有要求调用的方法名称,则表示不是请求调用服务器端的方法.
// 则返回一段js脚本,这段脚本作为在客户端的一个代理,代理的是服务器上
// 标识有AjaxMethodAttribute属性的方法.

if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "Render class proxy Javascript" );
}

context.Response.ContentType = "text/plain";
//RenderClientScript方法是AjaxProcessor类中的方法,功能是把某个类中标识有AjaxMethodAttribute属性的
//方法以js脚本的形式输出的客户端中.
ajaxer.RenderClientScript( mi, type );

// Some IAjaxObjectConverter need some Javascript code to build the
// strings that will be send to the server.

IAjaxObjectConverter converter;
StringBuilder _sb = new StringBuilder();
StringCollection sc = new StringCollection();


if ( Utility.AjaxConverters != null ) ...{

foreach ( Type t in Utility.AjaxConverters.Keys ) ...{
converter = (IAjaxObjectConverter) Utility.AjaxConverters[ t ];


if ( converter.ClientScriptIdentifier != null && sc.Contains( converter.ClientScriptIdentifier ) ) ...{
continue;
}

converter.RenderClientScript( ref _sb );
sc.Add( converter.ClientScriptIdentifier );
}
}


if ( _sb.Length > 0 ) ...{
context.Response.Write( _sb.ToString() );
}


if ( context.Trace.IsEnabled ) ...{
context.Trace.Write( "Ajax.NET", "End ProcessRequest" );
}
}
关于这里用到和AjaxProcessor类中的一些帮助方法以及.NET对象和JSON之间的转换等这方面的内容没有写得很清楚,留给下一篇吧.









































































































































































































































































































































































































关于这里用到和AjaxProcessor类中的一些帮助方法以及.NET对象和JSON之间的转换等这方面的内容没有写得很清楚,留给下一篇吧.