极地银狐.NET

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  152 随笔 :: 11 文章 :: 1297 评论 :: 11 引用

现在仿佛比较流行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,方便编程。

 

 

0
0
(请您对文章做出评价)
« 上一篇:[程序员生活]程序员失眠解决方案
» 下一篇:[连载]Tuning .NET Performance<1>
posted on 2006-02-20 02:56 极地银狐.NET 阅读(8057) 评论(35)  编辑 收藏 网摘 所属分类: 开发人生, 代码天下

评论

#1楼 2006-02-20 08:18 pwqzc[未注册用户]
好文
收藏先

  回复  引用    

#2楼 2006-02-20 10:56 mimi[未注册用户]
分析的挺不粗,但是Ajax。net是实现还是显得不是那么自然,我觉得MagixAjax挺不错的,推荐一下。
  回复  引用    

#3楼[楼主] 2006-02-20 11:14 极地银狐.NET      
嗯,谢谢,有机会我也看看MagixAjax。
  回复  引用  查看    

#4楼 2006-02-20 15:46 kim      
好文章啊~~

  回复  引用  查看    

#5楼 2006-02-20 17:10 春[未注册用户]
我发现提供的源代码编译之后。进行测试我发现有问题。无法正常提交数据。后来转用网上直接写好的AJAX确正常。不知道是什么原因。
  回复  引用    

#6楼 2006-02-20 17:12 春[未注册用户]
提供下载的代码有问题。编译成DLL文件之后进行测试发现无法正常提交数据到服务商当中。是否修改过源代码?记得以前的命名空间也不是这样定义
  回复  引用    

#7楼 2006-02-20 17:20 lichdr      
几年月前,用这个东西实现了一下树的操作。

还没空看它的实现,楼主捷足先登了。

  回复  引用  查看    

#8楼[楼主] 2006-02-20 17:39 极地银狐.NET      
@Kim: 谢谢啊,呵呵。

@春: 这是我从ajax.net网站上下载的代码,没有问题。你遇到的错误可能是因为我使用的是VS2005造成的。因为当时没有下载for 2005的版本,而是用2003的版本直接升级到2005使用的,所以可能在2003下无法编译,在此说声对不起。至于命名空间的不同,是因为此开源项目已在BorgWorX下,请访问http://ajax.schwarz-interactive.de/csharpsample/default.aspx 页面的最上方有通知:
The development of the Ajax.NET library has been stopped. On my private time I'm still developing on an AJAX library for the Microsoft .NET Framework. You can download my latest library here, it is called Ajax.NET Professional, now. BorgWorX is developing a commercial Ajax.NET library that is using the latest sourc code of the Ajax.NET library. The BorgWorX Ajax.NET version is an open source project and includes web controls that are using AJAX methods to update itself.

@lichdr :呵呵,来握手,以后请多指教!!

  回复  引用  查看    

#9楼 2006-02-21 08:10 ceocio      
good
  回复  引用  查看    

#10楼 2006-02-21 08:17 ceocio      
我比较感兴趣的是里面对attribute的运用。
  回复  引用  查看    

#11楼[楼主] 2006-02-21 13:06 极地银狐.NET      
@ceocio :
呵呵,用的很巧妙,可谓淋漓尽致啊。

  回复  引用  查看    

有个问题,ajax.net的不能定义同名的方法,即使参数列表不一样。也就是说一个类里不能有同时公布两个重载的ajax方法。否则调用出错,不知道怎么回事?
  回复  引用    

#13楼[楼主] 2006-03-02 12:18 极地银狐.NET      
@huguojunsy:这个问题不在Ajax.NET本身,在反射的时候你可以看到同样名称的函数也会被反射出来。主要问题我想出在JS上边。
  回复  引用  查看    

#14楼 2006-03-06 14:14 winking[未注册用户]
能不能把vs2003的版本提供下载?谢谢
  回复  引用    

#15楼[楼主] 2006-03-10 09:37 极地银狐.NET      
VS2003下的版本在AJAX.NET的网站上已经有了,你可以直接下载.
  回复  引用  查看    

#16楼 2006-03-14 14:39 ts[未注册用户]
https://svn.borgworx.net/SVN/BorgWorX/trunk/Web/Core/Ajax/
这个版本代码和你的有些不一样

那个新一些?谢谢

你的这个版本,我在03上编译过了,但加在项目里面不好使

  回复  引用    

#17楼[楼主] 2006-03-15 17:40 极地银狐.NET      
我用的版本是2005年的时候的了, 写这文章的时候没有下载最新的版本, 听说又出来了AJAX的控件.

这个东西在项目中还比较好用啊.

  回复  引用  查看    

#18楼 2006-03-16 09:12 ts[未注册用户]
AjaxProcessor.cs文件中
StreamReader sr = new StreamReader( Assembly.GetCallingAssembly().GetManifestResourceStream( "BorgWorXWeb.Core.Ajax." + commonAjax ) );

我的程序在这里找不到ajax.js,或者是没加载上,我检查了命名空间,没发现问题
不清楚是什么原因?

  回复  引用    

#19楼[楼主] 2006-03-16 09:27 极地银狐.NET      
@ts:
你在项目文件中是否包含有ajax.js?你参考一下本文章的第一张图。
可能是你没有下载到这个文件?

  回复  引用  查看    

#20楼 2006-03-16 12:11 ts[未注册用户]
有ajax.js这个文件,就是加载不上,
我查了一些资料,GetManifestResourceStream加载不上可能由于命名空间的问题,实在找不到什么原因了

  回复  引用    

#21楼[楼主] 2006-03-20 23:27 极地银狐.NET      
那是命名空间有问题了?
  回复  引用  查看    

好东西,
  回复  引用    

@pcletian
我喜欢

  回复  引用    

#24楼 2006-06-02 22:25 远方[未注册用户]
看了半天,看到云里雾里了
  回复  引用    

#25楼 2006-06-02 22:26 远方[未注册用户]
看了半天,看到云里雾里了
  回复  引用    

#26楼 2006-08-06 22:44 Crazy石头      
恩,需要研究。
  回复  引用  查看    

#27楼 2006-10-08 02:01 ryr[未注册用户]
rytryryry
  回复  引用    

#28楼 2006-10-08 02:01 ryr[未注册用户]
ggggggggggggg
  回复  引用    

#29楼 2006-10-08 02:02 ryr[未注册用户]
rrrttr
  回复  引用    

#30楼 2006-10-18 15:30 sek[未注册用户]
不知道为什么我的电脑上建立的Ajax项目
/ajax/common.ashx这个文件找不到,所以Ajax也失效
但改别人的源代码时,这个文件又找的到,我自己建的就不行,不知道什么原因

  回复  引用    

没有人回复吗?vs2005.net,我也是同样的问题。03可以
  回复  引用    

#32楼[楼主] 2006-11-10 15:51 极地银狐.NET      
@李强[匿名]
源代码有什么不同吗?先对比一下.
如果一样....那我也不清楚了.没有遇到过.呵呵.

  回复  引用  查看    

#33楼 2007-03-21 22:56 静水流深      
down下来看看,谢谢了
  回复  引用  查看    

我正要用呢
  回复  引用