当获得一个处理本次请求的Handler后,就可以在其ProcessRequest(异步为BeginProcessRequest)执行指定的方法。要执行一个页面对象的方法,我们必须知道指定页面所在的程序集,名称空间,页面类的名称以及方法的名称。这似乎符合我们前面:名称空间.类名称.方法名称的调用方式。为了与一般请求区分开,让组件具有足够的独立性,ajaxpro只拦截符合"ajaxpro/*.ashx格式的请求,这说明我们的ajax请求也要符合这个格式。如::50712/ajaxpro/AjaxProNamespace.AjaxProPage,TestAjaxProSourceCode.ashx,这个格式由前台脚本自动生成,并不需要我们去构造。仔细观察,会发现AjaxProNamespace.AjaxProPage,TestAjaxProSourceCode 就是页面类的完全限定名:名称空间.类名称,程序集名称,通过这个我们就可以生成具体的Type,然后进行反射获取信息。那么方法的名称呢?ajaxpro将其放在http header 中,名称为:X-AjaxPro-Method。有了这些信息,就可以反射执行方法了。这里核心代码为:
internal void Run() { try { //设置输出结果不缓存(这不一定是我们想要的) p.Context.Response.Expires = 0; p.Context.Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache); p.Context.Response.ContentType = p.ContentType; p.Context.Response.ContentEncoding = System.Text.Encoding.UTF8; //验证ajax请求 if (!p.IsValidAjaxToken()) { p.SerializeObject(new System.Security.SecurityException("The AjaxPro-Token is not valid.")); return; } //方法参数对象数组 object[] po = null; //请求处理结果 object res = null; try { //获取参数 po = p.RetreiveParameters(); } catch (Exception ex){} //获取缓存的Key string cacheKey = p.Type.FullName + "|" + p.GetType().Name + "|" + p.AjaxMethod.Name + "|" + p.GetHashCode(); if (p.Context.Cache[cacheKey] != null) { //如果缓存存在,则直接使用缓存 p.Context.Response.AddHeader("X-" + Constant.AjaxID + "-Cache", "server"); p.Context.Response.Write(p.Context.Cache[cacheKey]); return; } try { if (p.AjaxMethod.IsStatic) { //使用反射调用静态方法 try { res = p.Type.InvokeMember( p.AjaxMethod.Name, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod, null, null, po); } catch (Exception ex){} } else { try { //创建实例对象,反射调用实例方法 object c = (object)Activator.CreateInstance(p.Type, new object[] { }); if (c != null) { res = p.AjaxMethod.Invoke(c, po); } } catch (Exception ex){} } } catch (Exception ex){} try { //判断结果是不是xml,如是设置ContentType if (res != null && res.GetType() == typeof(System.Xml.XmlDocument)) { p.Context.Response.ContentType = "text/xml"; p.Context.Response.ContentEncoding = System.Text.Encoding.UTF8; ((System.Xml.XmlDocument)res).Save(p.Context.Response.OutputStream); return; } string result = null; ; System.Text.StringBuilder sb = new System.Text.StringBuilder(); try { result = p.SerializeObject(res); } catch (Exception ex){} //如果需要缓存,则将结果写入缓存 if (p.ServerCacheAttributes.Length > 0) { if (p.ServerCacheAttributes[0].IsCacheEnabled) { p.Context.Cache.Add(cacheKey, result, null, DateTime.Now.Add(p.ServerCacheAttributes[0].CacheDuration), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null); } } } catch (Exception ex){} } catch (Exception ex){} }
三、总结
我们总结一下ajaxpro的核心处理流程,它通过一个IHttpHandlerFactory拦截指定格式的url,然后从中获取类型的完全限定名生成类型对象,接着通过反射获取标记方法的特性,生成一个自定义的实现IHttpHandler接口的对象;在其ProcessRequest方法中,从http headers获取方法名称,通过反射进行参数映射并执行函数。
ajaxpro 具有如下优点:
1. 配置简单。
2. 可以配合其它组件一起使用。
3. 封装前台脚本,我们不用自己封装或者使用其它脚本库。
4. 对返回值处理,我们可以返回简单类型或者复杂类型都会自动序列化。
缺点是:
1. 页面会多出4个请求。尽管会利用304缓存,但还是需要发送请求到服务器。