Asp.NET Ajax学习笔记(4) -- Ajax.NET源程序分析2

           上次写到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,
                                    
nullnull, 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之间的转换等这方面的内容没有写得很清楚,留给下一篇吧.
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值