Ajax.NET源码分析

现在仿佛比较流行AJAX了。05年底从网上下了一个Ajax.NET在项目中应用过,感觉不错,来的方便量又足:)。结果就一直放在一边没有管它了。这几天心血来潮拿出来看它的源代码。如果有想要的朋友,请从这儿下载

 

相关网站:http://ajax.schwarz-interactive.de/csharpsample/default.aspx

 

打开AJAX源代码一看,一个解决方案里就一个项目,生成后也是一个DLL,很方便。

在分析源代码之前建议大家使用一下它,具体的应用方法在上边的链接已经能很清楚的找到,如果想要看中文的帮助文档,请访问这位老兄的文章:

http://herony420.cnblogs.com/archive/2006/02/16/331949.html

写的很完善。

 

前置条件:了解AJAX的大概运作机制。可以参考ASP实现XMLHttpRequest

 

好,现在我们就从粗线条入手,大概地了解一下这个library是怎么运作的。

上图是AJAX的项目文件组织情况。

 

基本思路:

1、  配置好web.config后,按正常情况加载页面;

2、  加载页面的page_loag事件中注册AJAX

3、  页面加载完成后马上产生第一次请求,注意,这不是一个xmlHttpRequest

4、  服务端实例化关于XmlHttpRequest和其它一些要使用的Javascript代码,发送到客户端来。

5、  客户事件可以利用异步请求进行工作了。这些请求会被web.config中指定的类intercept掉,服务端处理相关请求,返回结果。

 

配置web.config

具体内容如下:

< httpHandlers >

                     
< add  verb ="POST,GET"  path ="ajax/*.ashx"  type ="BorgWorX.Web.Core.Ajax.PageHandlerFactory, BorgWorX.Web.Core.Ajax" />

        
</ httpHandlers >



关于ashx文件,网上的资料不是很多,能用的就更少。它在这儿的作用是让BorgWorX.Web.Core.Ajax.PageHandlerFactory类返回一个IHttpHandler并处理之。当向服务器请求时,都会被IHttpHandlerFactory拦下来。

page_load事件中,有一段代码:

BorgWorX.Web.Core.Ajax.Utility.RegisterTypeForAjax( typeof (WebForm1));

主要作用是向客户端输出一段JS

< script type = " text/javascript "  src = " /ajaxTest/ajax/common.ashx " ></ script >

< script type = " text/javascript "  src = " /ajaxTest/ajax/ajaxTest.WebForm1,App_Web_6jqhtozc.ashx " ></ script >

客户端执行这段代码后,就开始向服务器请求ajax/common.ashx这个文件了,但不会被请求到,因为在被PageHandlerFactory拦截后,服务器就已经根据情况(主要是看context.Request[ "_session" ]的值)返回不同的IHttpHandler

第一次请求时返回的是一个AjaxHandlerSessionStateR,它的构造函数直接使用的是它的基类AjaxHandlerAjaxHandler重写了ProcessRequest方法,于是此方法执行:

AjaxRequestProcessor proc  =   new  AjaxRequestProcessor( context );

proc.Run();

 

在第一次请求中,proc.Run();是关键,它向客户端输入了很多javascript代码,包括产生异步调用的代码和客户端的“DataSet”等。

异步调用的代码,是放在Ajax.JS文件里的,在proc.Run();的时候用AjaxProcessorRenderCommonScript

/// <summary>

      
/// Render common script to the Response.

      
/// </summary>


      
internal   void  RenderCommonScript()  {

            
// We have to use different common javascript source for

            
// Windows Mobile PCs and all other browsers (IE, Firefox, Safari, Netscape, Opera)

 

            
string commonAjax = "ajax.js";

 

            
if ( context.Request.UserAgent.IndexOf( "Windows CE; PPC;" ) >= 0 ) {

                  commonAjax 
= "ajax_mobile.js";

            }


 

            StreamReader sr 
= new StreamReader( Assembly.GetCallingAssembly().GetManifestResourceStream( "BorgWorX.Web.Core.Ajax." + commonAjax ) );

            Write( sr.ReadToEnd() );

            sr.Close();

 

            Write( 
"var ajaxVersion = '5.7.22.2';" );

      }

 

此处因为 Ajax.JS 是内嵌资源,所以用 GetManifestResourceStream 来进行读取并输出,而且这些输出是在客户端发送 request 后的,所以我们通过右键看源代码也看不到。

当客户端把response出来的JS加载完后,第一次页面的loading才算完成。

 

对于已经加载完毕的页面发送的异步请求,比如返回两个整数相加的值(函数签名为public int ServerSideAdd(int firstNumber, int secondNumber)Ajax.NET是这么处理的:

首先在客户端异步向服务器post,服务器这边由PageHandlerFactory拦截,并分析context.Request[ "_session" ]的值,通过分析发现该值匹配context.Request[ "_session" ] == "no",于是执行return new AjaxHandler();随后fire AjaxHandlerProcessRequest

public   override   void  ProcessRequest( HttpContext context )  {

            AjaxRequestProcessor proc 
= new AjaxRequestProcessor( context );

 

            proc.Run();

      }

这儿我们应该可以猜到所有的事都交给Run来完成了。好,我们深入进去看看。

Run的代码里有这么一句:

Line 49:

DateTime now  =  DateTime.Now;

也许有人奇怪这是为什么,还加个时间,其实这个时间在后边作缓存时是有用的。

 

Line 57:

AjaxProcessor ajaxer  =   new  AjaxProcessor();

ajaxer.InitializeContext( 
ref  context );

实例化一个AjaxProcessor,后边有用。

  Line 64:

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

此时为false,所以不用再执行方法ajaxer.RenderCommonScript();(line 72)了。

 

Line 87:

Type type;

MethodInfo[] mi 
=   null ;

string  methodName  =   null ;

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

string  md5  =   null ;

StreamReader sr 
=   null ;

 准备反射和内存流读取。

下图为type的实例化:

 

Line 99:

byte [] b  =   new   byte [context.Request.ContentLength];

设置读取的buffer

  Line 100:

if  ( context.Request.HttpMethod  ==   " POST "   &&  context.Request.InputStream.Read( b,  0 , b.Length )  >=   0  )

此时返回为true,以下代码被执行。

  Line 101:

md5  =  MD5Helper.GetHash( b );

返回的md5是一串排列好了的hash codeMD5Helper的这个方法封装了MD5CryptoServiceProviderComputeHash方法,在后边会把这个md5和刚才我们得到的时间一起在缓存时使用。

  Line 102:

sr  =   new  StreamReader(  new  MemoryStream( b ), UTF8Encoding.UTF8 );

开始流的读取。

 

Line 104:


if  ( context.Cache[ type.FullName  +   " | "   +  md5 ]  !=   null  )  {

                       context.Response.Write( context.Cache[ type.FullName 
+ "|" + md5 ].ToString() );

}

如果允许缓存,则直接使用之,它好我也好。

  Line 119:

MethodInfo method  =  type.GetMethod( methodName );

 

                  
if  ( method  !=   null  )  {

                       
object[] ii = method.GetCustomAttributes( typeof (AjaxMethodAttribute), true );

 

                       
if ( ii.Length != 1 ) {

                             
// the method does not have one 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;

                       }

开始反射。

如图:

记的我们在使用AJAXNET的时候要在公有方法前加一个

[BorgWorX.Web.Core.Ajax.AjaxMethod()]这样的属性吗?现在有用了。不过ii.Length != 1将会为false,所以不会return,代码继续往下走。

  Line 139

ParameterInfo[] para  =  method.GetParameters();

po 
=   new   object [para.Length];

try   {

// the AjaxProcessor will read the values either form the 

// request URL or the request input stream.

ajaxer.RetreiveParameters( 
ref sr, para, ref po );

继续反射,RetreiveParameters最后会让para去填充po的。现在po可以直接使用了。此方法中代码会检查context.Request[ "_return" ] != null && context.Request[ "_return" ] == "xml"并实例化一个hashtable,通过sr.ReadLine();把传入的两个参数先进行replace处理,主要是%=号,然后通过字符串操作把=号剥离并放入hashtable中,两个参数一共放两次。最后将hashtable中的两个object转化为正确的类型。

Line 156:

object  o  =   null ;

o是用来放结果的。

  Line 191:

object  c  =  ( object ) Activator.CreateInstance( Type.GetType( typeName ),  new   object []  {}  );
if  ( c  !=   null  )  {
= method.Invoke( c, po );
}

利用反射创建一个page类,并调用其方法,参数是刚才存入hashtable中的值。

 

最后,向客户端response 输o,异步调用完毕。

Ajax.NET引入了JSON(JavaScript Object Notation),具体请参考http://www.json.org/

下图是JSON的使用情况:

 

小结:

AJAX.NET的创意点:

1、             Ajax.js文件的嵌入;

2、             异步调用的服务器端处理,没有涉及到页面,较好的复用性;

3、             使用反射直接计算值(但不知道performance test表现如何);

4、             缓存机制;

5、             整合 JSON ,方便编程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值