问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

AjaxPro怎么才能做到一个页面包含很多常用函数?

发布网友 发布时间:2022-05-15 01:08

我来回答

3个回答

懂视网 时间:2022-05-15 05:29

ajaxpro虽然是一个比较老的组件,不过实现思想和源码还是很有借鉴价值的。接下来通过本篇文章给大家介绍编写轻量ajax组件02--浅析AjaxPro,感兴趣的朋友可以参考下

前言

  上一篇介绍了在webform平台实现ajax的一些方式,并且实现一个基类。这一篇我们来看一个开源的组件:ajaxpro。虽然这是一个比较老的组件,不过实现思想和源码还是值得我们学习的。通过上一篇的介绍,我们知道要调用页面对象的方法,就是靠反射来实现的,关键是整个处理过程,包括反射调用方法、参数映射等。ajaxpro不仅在后台帮我们实现了这个过程,在前台也封装了请求调用的方法,例如ajax的相关方法,用ajaxpro的方法就可以发送异步请求了,不需要自己封装js或者使用js库。接下来就对这个组件进行浅析。

一、ajaxpro的使用

  我们先来看这个组件如何使用。

  1. 注册AjaxHandlerFactory

  在web.config里进行如下配置:

  简单的说,请求的url符合 ajaxpro/*.ashx 格式的,都会被AjaxHandlerFactory处理,这是一个实现IHandlerFactory接口的工厂类,用来获取IHandler处理程序。其中type的格式是:"名称控件.类名称,程序集名称"。

  2. 在页面类Page_Load事件进行注册

  我们传递了本页面对象的Type给ResisterTypoForAjax方法,这个方法用来在前台注册脚本,具体会调用当前Page对象的RegisterClientScriptBlock进行注册,所以.aspx文件中必须有一个<form runat="server"></form>,否则脚本将无法注册。(这里传递了Type,实际也可以做到不用传递的,内部通过HttpContext.Current.Handler.GetType().BaseType 也可以获得这个类型)

  3.用AjaxMethod标记方法  

  AjaxMethod是一个标记属性,表示这个方法用于处理ajax请求,它最终通过反射执行;它有几个构造函数对,对于有些需要缓存的数据,可以设置缓存时间;如果我们的请求不需要使用Session,可以设置HttpSessionStateRequirement;如果请求需要异步,例如请求一个耗时的web服务,也可以设置处理程序为异步状态。

  方法的返回值可以是简单的类型,也可以是复杂的类型;例如集合类型在前台获得就是一个数组。

  4.前台调用

  后台的配置和使用都非常简单,接下来我们看前台如何发起请求。

  这里AjaxProNamespace 是页面类所在的名称空间,AjaxProPage 就是页面类的名称,GetList是标记的方法。为什么可以这样写呢?前面说到,ajaxpro会在前台注册脚本,它会根据我们页面对象的相关信息生成如下脚本,所以我们才可以这样调用,而完全不用自己写js或者用jquery库的方法。

  GetList的参数对应后台方法的参数,类型必须可以转换,否则调用会失败。最后一个参数为回调函数,回调函数的参数是对返回结果进行封装的对象,其value属性就是执行成功返回的值,如上面返回的就是一个数组对象。其error包括了失败的信息。

  注意,上面注释掉的部分是同步请求的做法,这往往不是我们想要的,我曾经就见过有人这样错误的使用。

二、ajaxpro处理请求原理

  这里主要关注组件处理ajax请求的过程,其它辅助功能不做介绍。

  1.生成辅助脚本

  在Page_Load事件里我们调用了AjaxPro.Utility.RegisterTypeForAjax(typeof(AjaxProPage)); 用来注册所需要的脚本。我们注意到在前台页面引入了如下脚本:

也就是每个页面都会都会发起这几个请求。这几个都是.ashx结尾的文件,但实际里面都是js代码;这些js有的是作为资源嵌套在dll内部,有的是自动生成的,主要是封装了ajax请求相关方法,以及让我们可以用:名称空间.页面类名称.标记方法名称 这样去调用方法。为什么要用.ashx而不是用.js呢?因为作为组件内部的资源文件,外部无法直接请求.js文件,而.ashx可以被拦截,然后用Response.Write将内容输出。

  如果每次都生成和发送这些脚本的效率是很低的,ajaxpro内部的处理是判断请求头的If-None-Math和If-Modified-Since,如果两个都和缓存的一样,就返回一个304状态码。所以,客户端只有首次请求服务端会返回文件的内容,后续的都只返回304表示使用本地缓存。我们刷新页面可以验证这个过程:

  2. 拦截请求

  HttpHandler(IHttpHandler) 和 HttpModule(IHttpModule) 是asp.net 两个重要的组件,让我们可以在asp.net的基础上很方便的进行扩展。HttpHandler对应某种具体的请求,例如.ashx,.aspx等;HttpModule是一个拦截器,可以在管道的某个事件对所有请求进行拦截。简单的说,在管道中,HttpApplication会触发一系列事件,我们在通过HttpModule对某个事件进行注册,例如我们可以在处理程序对象生成前拦截请求,然后映射到自己的处理程序;而实际处理请求返回结果的是HttpHandler,例如Page用来生成html。

  以asp.net mvc框架为例,它是建立在asp.net 路由机制的基础上的,asp.net 路由系统通过一个UrlRoutingModule对请求进行拦截,具体是在PostResolveRequestCache事件进行拦截,对url进行解析,封装相应的路由数据后,最终将请求交给一个MvcHandler进行处理,MvcHandler实现了IHttpHandler接口。

  前面我们进行了如下配置:<add verb="POST,GET" path="ajaxpro/*.ashx" type="AjaxPro.AjaxHandlerFactory, AjaxPro"/> 这表明了任何的以 ajaxpro/任意名称.ashx结尾的 Post/Get 请求,都交给AjaxPro.AjaxHandlerFactory进行处理,它是一个实现了IHandlerFactory的处理程序工厂,用来生成具体的IHttpHandler。组件内部定义了多个实现IHttpHandler的类,有的是为了生成js脚本的,对于处理ajax请求,主要分为两类:异步(IHttpAsyncHandler)和非异步(IHttpHandler);在这两类的基础上,对于Session的状态的支持又分为三种:支持读写(实现IRequiresSessionState标记接口)的Handler、只读(实现IReadOnlySessionState标记接口)的Handler和不支持Session的Handler。具体生成什么样的Handler是通过AjaxMethod进行判断的。

  IHttpHandler的ProcessRequest(异步就是BeginProcessRequest)就用来执行请求返回输出结果的。如果只需要一种处理程序我们也可以实现IHttpHandler。IHandlerFactory的定义如下:

  所以,ajaxpro的所有请求都会符合ajaxpro/*.ashx格式,然后在GetHandler方法,就可以进行具体的处理,返回结果是IHttpHandler;以非异步状态为例,如果我们配置了需要Session,就会生成一个实现IHttpHandler和IRequiresSessionState的Handler,如果需要只读的Session,就会生成一个实现IHttpHandler和IReadOnlySessionState的Handler;这些信息可以通过反射从AjaxMethod标记属性获得。AjaxHandlerFactory的主要代码如下:

  3. 反射执行方法

  当获得一个处理本次请求的Handler后,就可以在其ProcessRequest(异步为BeginProcessRequest)执行指定的方法。要执行一个页面对象的方法,我们必须知道指定页面所在的程序集,名称空间,页面类的名称以及方法的名称。这似乎符合我们前面:名称空间.类名称.方法名称的调用方式。为了与一般请求区分开,让组件具有足够的独立性,ajaxpro只拦截符合"ajaxpro/*.ashx格式的请求,这说明我们的ajax请求也要符合这个格式。如:http://localhost:50712/ajaxpro/AjaxProNamespace.AjaxProPage,TestAjaxProSourceCode.ashx,这个格式由前台脚本自动生成,并不需要我们去构造。仔细观察,会发现AjaxProNamespace.AjaxProPage,TestAjaxProSourceCode 就是页面类的完全限定名:名称空间.类名称,程序集名称,通过这个我们就可以生成具体的Type,然后进行反射获取信息。那么方法的名称呢?ajaxpro将其放在http header 中,名称为:X-AjaxPro-Method。有了这些信息,就可以反射执行方法了。这里核心代码为:

输出结果不缓存(这不一定是我们想要的)
 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缓存,但还是需要发送请求到服务器。

  2. ajax无法使用Get请求。由于自定义了url格式,使用这种格式就无法用Get请求了,我们知道Get请求是可以被浏览器缓存的,雅虎前端优化建议中有一条就是多用get请求。事实上,应该把名称空间.类名称,程序集放到http header中,然后提供了一个type类型的参数让我们自由选择。

  3. 与<form runat="server">绑定。目的是用了为我们生成前台脚本,但如果我们希望用.html文件 + .aspx.cs 的方式就不能用了(博客园有些页面就用了这种方式);甚至我们的接口可能要给移动端使用,这种方便就变成了限制。

  4. 反射。这样效率是比较低的,它甚至没有像我们之前的页面类一样,对MethodInfo进行缓存。

  可以看出,如果在不太计较效率的情况,这个组件还是值得使用的。这里只是做一个核心的介绍,里面还有很多其它功能,这是ajaxpro组件的源代码,有兴趣的朋友可以研究研究。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

浅析json与jsonp区别及通过ajax获得json数据后格式的转换

Django框架利用ajax实现批量导入数据功能

AJAX XMLHttpRequest对象详解

热心网友 时间:2022-05-15 02:37

可以调用的。。 我一般就只写一个页面的AJAX方法,其他页面要调用的话。。。只要把生成的四行AJAX方法调用的脚本引用进来即可,那四行从哪里来呢。。。可以这样做。
首先创建AJAX方法实现的页面 [AjaxPage.aspx] 里面把需要的代码写好后,在浏览器中查看生成以后的源文件。会发现如下四行
<script type="text/javascript" src="/WEBTEST/ajaxpro/prototype.ashx"></script>
<script type="text/javascript" src="/WEBTEST/ajaxpro/core.ashx"></script>
<script type="text/javascript" src="/WEBTEST/ajaxpro/converter.ashx"></script>
<script type="text/javascript" src="/WEBTEST/ajaxpro/WEBTEST.FunctionPage.AjaxPage,AjaxPage.ashx"></script>

OK,这四句拷贝下来,以后在其他页面中直接把这四行加到<head></head>或者是<body></body>里面就可以了。。。不用再定义其他的AJAX方法,即可以访问AJAXPage中写的。。 有了这四句,哪怕是在 .html 这类的纯静态页面中都可以实现。

建议楼主多了解一下ajax的实现机制及原理,而不仅仅是学习如何使用现成的组件。

热心网友 时间:2022-05-15 03:55

我的做法是单独写一个cs文件,文件中写一个公共类,类中定义多个非ajaxpro函数。
然后在每个需要用他的页面定义各自的ajaxpro方法,但这些方法不写具体的方法实现,而是调用公共类中的各个非ajaxpro方法。也就是利用ajaxmethod进行一个过度。这样既可以实现ajax 又能尽量公用已有代码

ajaxpro就是这样,由于每个页面都是一个类,所以调用的时候代码基本不能公用的
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
焦作有哪些旅行景点值得一去? 河南穿古装去的地方 AE入门从学会套模板开始,AE模板套用简易教程,看起来复杂的AE其实也很... ae怎么套用模板ae模版的使用方法 北京通州区有什么好玩的地方吗 请问现在有哪些看电影的网站?越多越好~~ 帮初中女儿请假一天讲身体不适,班主任却跟别的老师讲她得了大病,该如何... 梦见家中被盗空只剩一件绿色衣的预兆 梦见美丽沙穗 美版4s内置卡贴有什么危害? 网线三通头就是网线一分二的那个东西和交换器的区别。同样都能供两台电脑使用? 浙江省最大的十座水库 江山的水库移民补助款今年怎么没有 小红家计划办一个家庭养殖场。养殖场办好后每年可以养50头猪和30头羊,但修房舍需要8800元,这些猪和羊一年 支付宝被骗钱报警有用吗 网线一分二转接头能不能反过来接 它里面是不是互通的 为什么射频转接头里面只有三通(比如:1个BNC公,2个BNC母),却很少看到有四通或者五通转接头? 我同学被 支付宝的骗子骗了6000千多。是自己转出去的,报警的话会管吗,几率大不大 坐井观天不计其数,成千盈百兴高采烈,奇峰怪石,成群结队,雍容尔雅,刻舟求剑,愁 请用成千盈百造句 成语填空“成()盈()”? 什么千什么百的成语。例:成千盈百。 与成千盈百相近得成语3个 什么千什么百 成千盈百的盈的意思 成千盈百是表示人多的词语吗? 成千盈百的盈是什么意思,热泪盈眶的盈是什么意思。 成百盈千的意思 谁知道成语《成千盈百》的意思 成千盈百是什么意思 我的手机转接到别人的手机号上了。我能知道都谁给他打电话了吗? 两个手机同用一个id,可以看到谁打电话给对方嘛? 手机没电关机了,别人给我打了电话,等开机后要怎么才知道有人给我打电话呢 ? 张东健的电影《朋友》中插曲求助! 韩国电影[朋友] 中的一段插曲 一部关于朋友的电影 公众有什么作用 柚子的柚的组词 小腿不直,穿裤子什么的很难看,怎么办 柚可以组什么词 腿不直,有点O型,而且很瘦,175CM,50公斤多点,怎么穿裤子和衣服 怎样穿裤子可以让自己的腿看起来更直了? 请问专家或专业人士,我这属于什么腿型?感觉太不直了,穿裤子小腿特别难看,如何矫正??在线等答案 带皮驴肉要炖多久 Ajax++的发展历史 柚子的近义词是什么 杭州拱墅区交警大队双休能处理违章吗 杭州北景园交通违章处理点 煮驴肉大煮多久 杨幂连均码卫衣穿在身上都略大,好在细腿够抢镜,你怎么看呢?