基于.Net 写我自己的Ajax后台框架AjaxFramework

    小小目录:

  •     为什么要写自己的Ajax后台框架
  •     框架的简单设计说明
  •     框架如何使用
  •     框架使用效果图
  •     框架的优缺点
  •     框架源码下载

    1、为什么要写自己的Ajax后台框架

         现在Ajax在web应用方面已经用的稀巴烂了,如果你做一个网站没有用到ajax都不好意思拿出手,虽然面对ajax的潮流下,在.net开放方向,微软已经做了很多工作了,比如推出了ajax的服务器端控件,但是他不够灵活,用的人多吗?不多!

        在.Net环境下与ajax配合的几种情况(主要是针对webform,因为.net mvc你只要写action就可以将方法给发布出来,实现ajax的调用):

        1.用ajax访问aspx页面:直接在page_load中输出html代码并且End掉多余标签的输出,但是他还要走生命周期,一个好好的aspx页面只用这个功能怪怪的,当然还可以直接在aspx.cs上面的方法上加上[webMethod]特性来标记ajax访问,但是必须该方法为静态,用起来也不是很爽。

       2.用ajax访问ashx一般处理程序:这个是在.net的ajax开发中一种常见明确推荐的方式,他输出页面少,不冗余代码,调用灵活,但是他通常一个ashx页面只提供一个功能,但是市面上有可以通过switch方法的参数或者用委托或者反射的方法来实现一个ashx页面提供多个ajax访问的功能,但是没发现这样也挺乱的吗,我之前一直用这个,慢慢的 慢慢的开始讨厌这种写好写法!

      3.用ajax直接调用webservice服务:这样的好处是在一个普通的webserive类中可以使用多个对外ajax访问点的发布,用起来很灵活,但是你一般的小网站为了ajax的访问还是部署webservice还是比较烦的吧!

      4.用ajax去调用wcf:微软推出了wcf,并且现在公认为他是一种可以替代webservice的新产品,并且他还支持奖wcf部署在web服务器上,以url形式发布,当然了,这样就可以用ajax来访问调用,但是同上,小网站小应用还要去弄wcf,也是挺烦的一件事情!

      不知道大家发现没有,第一二中方法其实终于还是访问了业务类里面的方法,是否感觉ajax调ashx,aspx有些多余?还有第三四中方法其实可以看做业务类里面的方法,但是需要发布才可以使用,挺烦!那有没有可能让ajax直接去访问cs类里面的方法呢?

       我就开始查资料,看看网上别人的一些做法和看法,之前在.net方面有个叫做ajaxpro的dll可以实现cs发布成ajax,但是感觉使用起来还是有点复杂,就自己琢磨着自己能否开发一个.net的ajax后台框架,在普通cs类的方法上面稍加修饰,不改变方法原有功能,但是能将方法发布出来?

       2、框架的简单设计说明

       经过几点的奋战,终于有了一个初步可以用的版本,先贴上设计的类图:

       

         看了这个图是不是看上出还是比较繁琐?那接下来再来看下这个框架运行的泳道图应该就比较明了:

        

         他其实就分让相应的url进入指定的handlerfactory里面,这个factory去指定调用相应的handler(你可以看做ashx文件),然后去解析地址栏的url,得到具体的方法,再去动态执行,最后输出结果即可,大致流程就是这样,现在我来说一些细节:

        url的一些解析问题:本次设计的url例如:http://domain.com/classname/method.ajax?param...,从url里面可以解析得到此次请求的class类名以及具体的method方法名,当然所属的程序集是需要配置的好的,这样就可以通过反射具体得到方法

        如何得到方法:由于得到的类名,方法名都是字符串,我们知道可以使用.Net里面的反射功能来实现通过字符串去调用相应的方法,但是反射消耗的性能还是很大的,所以我做了缓存,在一个方法成功请求之后我就将该方法缓存起来,以便下一次的时候不需要再反射直接调用缓存.

View Code
 1 #region 获取该方法
 2 
 3             if (_idictMethod.Keys.Contains(this.DictKey))
 4             {
 5                 #region 存在缓存中 直接从缓存中取得
 6                 //如果该方法被访问过 存在该字典中
 7                 customMethodInfo = _idictMethod[this.DictKey];
 8                 //更新执行时间
 9                 customMethodInfo.LastUpdateTime = DateTime.Now;
10                 //访问次数加1
11                 customMethodInfo.Count++;
12                 //将调用后的信息反写进去
13                 _idictMethod[this.DictKey] = customMethodInfo;
14                 #endregion
15             }
16             else {
17                 #region 如果缓存中不存在 将会反射重新获取方法信息 并且记录缓存
18                 customMethodInfo = this.GetMethodBaseInfo();
19                 if (customMethodInfo == null)
20                 {
21                     throw new MethodNotFoundOrInvalidException(string.Format("没有找到方法{0}", this._methodPathInfo.MethodName));
22                 }
23                 else
24                 {
25                     #region 初始化方法的一些信息
26                     //特性列表
27                     customMethodInfo.AttrList = ReflectionHelper.GetAttributes<ValidateAttr>(customMethodInfo.Method);
28                     //参数列表
29                     customMethodInfo.ParamterInfos = customMethodInfo.Method.GetParameters();
30                     //返回值类型
31                     
32                     customMethodInfo.RetureType = customMethodInfo.Method.ReturnType;
33                     //方法最后的更新时间
34                     customMethodInfo.LastUpdateTime = DateTime.Now;
35                     //方法的执行次数
36                     customMethodInfo.Count = 1;
37                     #endregion
38 
39                     #region 加了双重锁  防止死锁掉 将该方法加入缓存
40                     //通过了特性的检测
41                     if (!_idictMethod.Keys.Contains(this.DictKey))
42                     {
43                         lock (obj)
44                         {
45                             //防止在锁的时候 其他用户已经添加了键值
46                             if (!_idictMethod.Keys.Contains(this.DictKey))
47                             {
48                                 //将 此方法的信息记录到静态字典中 以便下次从内存中调用
49                                 _idictMethod.Add(this.DictKey, customMethodInfo);
50                             }
51                         }
52                     }
53                     #endregion
54 
55                 }
56                 #endregion
57             }
58             #endregion

       并且为了尽量少反射,减少用户请求时间,在第一次程序运行的时候,我就将可能为标记ajax的方法给预缓存了起来(用静态构造方法可以实现该功能,该构造方法仅仅在第一次使用该类的时候运行,并且只运行一次)

View Code
 1 #region 初始化缓存
 2         /// <summary>
 3         /// 初始化缓存
 4         /// </summary>
 5         private  static void InitCache()
 6         {
 7             ICollection assemblies = BuildManager.GetReferencedAssemblies();
 8 
 9             foreach (Assembly assembly in assemblies)
10             {
11 
12                 if (UrlConfig.ASSEMBLY.Equals(assembly))
13                 {
14                     //如果在指定的ajax的业务的程序集中
15 
16                     //添加到程序集的缓存中
17                     if (!_idictAssemby.Keys.Contains(GetAssemblyName(assembly)))
18                     {
19                         _idictAssemby.Add(GetAssemblyName(assembly), assembly);
20                     }
21                     
22                     try
23                     {
24                         foreach (Type t in assembly.GetExportedTypes())
25                         {
26                             Type[] allInterface = t.GetInterfaces();
27                             foreach (Type interfaceName in allInterface)
28                             {
29                                 if ("IAjax".Equals(interfaceName.Name))
30                                 {
31                                     // 该类有IAjax的接口 则默认添加进缓存 添加到类的缓存中
32                                     if (!_idictClass.Keys.Contains(t.FullName))
33                                     {
34                                         _idictClass.Add(t.FullName, t);
35                                     }
36                                     
37                                 }
38                             }
39                         }
40                     }
41                     catch { }
42                 }
43 
44                 
45             }
46 
47             //针对方法添加缓存
48             foreach (string className in _idictClass.Keys)
49             {
50                 foreach (MethodInfo methodInfo in _idictClass[className].GetMethods(_bindingAttr))
51                 {
52                     try
53                     {
54                         List<ValidateAttr> attrList = ReflectionHelper.GetAttributes<ValidateAttr>(methodInfo);
55 
56                         //有标志的WebMethodAttr属性  添加进方法的缓存
57                         WebMethodAttr webMethodAttr = attrList.Find(x => x is WebMethodAttr) as WebMethodAttr;
58                         if (webMethodAttr == null)
59                         {
60                             //没有该特性
61                             continue;
62                         }
63                         CustomMethodInfo customMethonfInfo = new CustomMethodInfo()
64                         {
65                             AttrList = attrList,
66                             Count = 0,
67                             LastUpdateTime = DateTime.Now,
68                             Method = methodInfo,
69                             RetureType = methodInfo.ReturnType,
70                             ParamterInfos = methodInfo.GetParameters(),
71                             Instance = Activator.CreateInstance(_idictClass[className]),
72                             Assembly = _idictClass[className].Assembly
73 
74                         };
75                         //添加进方法的缓存里面去
76                         if (!_idictMethod.Keys.Contains(className+"."+methodInfo.Name))
77                         {
78                             _idictMethod.Add(className + "." + methodInfo.Name, customMethonfInfo);
79                         }
80                        
81                     }catch{}
82                     
83 
84                 }
85             }
86         }
87 
88         /// <summary>
89         /// 得到程序集的名称  不带版本信息的
90         /// </summary>
91         /// <param name="assembly"></param>
92         /// <returns></returns>
93         private static string GetAssemblyName(Assembly assembly)
94         {
95             return assembly.FullName.Split(',')[0];
96         }
97         #endregion

       这样就可以尽可能得降低反射因为消耗的性能而带来产生的效率问题!

       本框架在方法特性上作了扩展,以标记特性的方式可以对ajax方法做一些操作,比如参数的验证,缓存的输出等,并且该特性都是很容易扩展的,只要继承ValidateAttr类即可实现接口的扩展,为以后比如用户权限认证,访问量限制等需要提供很好的解决方案

View Code
 1 #region 检查方法的特性 (未完善)
 2         /// <summary>
 3         /// 检查方法的特性  (未完善)
 4         /// 现在主要是请求权限的验证 参数的验证
 5         /// </summary>
 6         /// <param name="methodInfo"></param>
 7         /// <param name="errMsg">验证失败时带出的消息</param>
 8         /// <returns></returns>
 9         private bool CheckAttribute(List<ValidateAttr> attrList)
10         {
11             bool ret = true;
12             if (attrList.Count > 0)
13             {
14                 foreach (ValidateAttr attr in attrList)
15                 {
16                     attr.CurrentHttpRequest = this._httpRequestDescription;
17                     #region 判断此特性是否能通过验证
18                     if (!attr.IsValidate())
19                     {
20                         //特性的验证规则失败
21                         ret = false;
22                         break;
23                     }
24                     #endregion
25                 }
26             }
27             else
28             {
29                 throw new MethodNotFoundOrInvalidException("此方法并不是网络方法,无法直接访问");
30             }
31 
32             return ret;
33         }
34         #endregion

       在不可或缺的参数验证特性上面简单的使用了策略模式,可以低耦合的实现其他一些参数类型扩展

View Code

     最后在页面输出方面,使用了一个简单的输出帮助以,以AjaxResult结果寄存类和json的一个序列化类就行输出

View Code
/// <summary>///  /// </summary>/// <param name="returnValue">返回值</param>/// <param name="returnType">返回类型</param>/// <returns>返回字符串</returns>public static string GetResponseString(object returnValue,Type returnType){string ret = string.Empty;try{if (returnType.IsSampleType()){//返回的是简单类型AjaxResult ajaxResult = new AjaxResult(){Flag = "1",Data = Convert.ToString(returnValue)};ret = ajaxResult.ToString();}else{ret = JsonConvert.SerializeObject(returnValue);}}catch (Exception ex){//遇到异常AjaxResult errResult = new AjaxResult(){Flag = "0",ErrorMsg = ex.Message};ret = errResult.ToString();}return ret;}/// <summary>/// 返回错误/// </summary>/// <param name="errorMessge"></param>/// <returns></returns>public static string ResponseError(string errorMessge){//返回错误AjaxResult errResult = new AjaxResult(){Flag = "0",ErrorMsg = errorMessge};return errResult.ToString();}

     3、框架如何使用

      本框架暂时命名为AjaxFramework,所以你在使用本框架时只需要引用该dll,然后在webconfig里面针对不同的IIS版本配置好相应的HttpHandler

View Code
<httpHandlers>
<!--针对IIS6  再这里配置handler 以支持ajax后缀的扩展--><add verb="*" path="*.ajax" validate="true" type="AjaxFramework.AjaxHandlerFactory,AjaxFramework" />
</httpHandlers><handlers>
<!--针对IIS7  再这里配置handler 以支持ajax后缀的扩展--><add name="ajaxhandler" verb="*" preCondition="integratedMode" path="*.ajax"  type="AjaxFramework.AjaxHandlerFactory,AjaxFramework" />
</handlers>

    这里的.ajax后缀根据你的需求修改,比如你可以修改成.json,以后以相应的后缀访问就可以了

     再配置好你需要公布的命名空间

View Code
<appSettings><!--在此处配置ajax后台框架所需映射的项目--><add key="AjaxFramewok" value="TestBLL"/></appSettings>

    至此,配置已经完成,是不是还算简单!

     用法就如下了

View Code

    这标明TestBLL空间里面的Data类里面的Add方法被发布了出来,是不是很简单,只需要添加相应的特性即可完成发布网络方法的操作

    然后你可以用http://domain.com/data/add.ajax?a=4&b=6.787的url形式就行访问了

    4、 框架使用效果图

     先来看一下上面一个章节里面那个发布方法的效果图:

     

      

       我们来看下用Get方式去访问Post标记方法的情况

View Code
/// <summary>/// 这个方法只有Post请求才可以/// </summary>/// <returns></returns>
        [WebMethodAttr(RequestType.Post)]public string Get_Pat(){return "pat";}

      

       我们来看下普通类型返回的情况

View Code
/// <summary>/// 返回普通的字符串 会加上一个json的外壳/// </summary>/// <returns></returns>
        [WebMethodAttr(RequestType.Get)][OutputCacheAttr(20)]public string Get_Pat2(){return "pat" + DateTime.Now.ToString("yyyyMMddHHmmssfff");}

      

       但是如果返回的是DataTable,会怎么样呢?

View Code
/// <summary>/// 返回DataTable的数据/// </summary>/// <returns></returns>
        [WebMethodAttr(RequestType.Get)]public DataTable Get_Data(){DataTable dt = new DataTable("dt");dt.Columns.Add("id");dt.Columns.Add("name");DataRow row = dt.NewRow();row["id"] = 1;row["name"] = "tom";dt.Rows.Add(row);DataRow row2 = dt.NewRow();row2["id"] = 2;row2["name"] = "peter";dt.Rows.Add(row2);return dt;}

       

       那么如果方法的参数是实体类型,我们该如何传呢?

View Code
/// <summary>/// 这个方法是用来测试传实体的/// </summary>/// <param name="user"></param>/// <returns></returns>
        [WebMethodAttr(RequestType.Get)]public User Insert_User(User user){return user;}

      

       估计方法+配图,大家应该看的很明白了吧!

       在这里提一下,由于现在ajax的请求返回类型基本都是json格式,所以本框架暂时只支持json格式!

       5、框架的优缺点

        先来说优点吧:

        1:你以后在使用ajax的时候不需要再加各种ashx,aspx页面,加上相应的特性即可将你业务层里面的方法给发布出来

        2:利用特性扩展这一特点可以很方便的满足你其他的要求

        3:运用了各种方式的缓存,效率应该不会将到哪里去

        3:整体框架还算简单,运行思路明了,相对wcf,webservice这些复杂的框架,以后出错可以手动调试源码

        估计缺点也有很多:

        1:由于是通过反射来运行方法的,某些时候效率可能会不怎么高

        2:在参数动态赋值模块对于其他的一些参数可能会有问题

        3:发布方法无法重载

        4:只是刚刚写出来,没有投入到实际项目中,可用性还有待商榷

 

          这个框架可以用哪里?

         一般的小OA,ERP,个人博客站,小的CMS站,普通企业站个人觉得这个框架还是可以应付的,如果需要在其他类型的网站上使用你就自己看着办吧!

        6、源码下载

        我厚着脸皮的发到了Github上面去,点我去Github下载AjaxFramework(json类库在lib文件夹中,可能需要重新引用一遍),希望有兴趣的同学可以加入进来一些开发哦,有问题留言吧,很期待您的指导!

转载于:https://www.cnblogs.com/yyl8781697/archive/2013/05/09/ajaxframework.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/575989.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL备份恢复与日志

MySQL 数据库的备份与恢复 1.1 备份数据的意义 第一是保护公司的数据&#xff0c;第二是网站7*24小时提供服务1.2 备份单个数据库参数使用 MySQL数据库自带了一个很好用的备份命令&#xff0c;就是mysqldump&#xff0c;它的基本使用如下&#xff1b;语法&#xff1a;mysqldum…

MySQL入门介绍

数据库介绍 1.1 什么是数据库&#xff1f; 简单的说&#xff0c;数据库&#xff08;英文Dtabase&#xff09;就是一个存放数据的仓库&#xff0c;这个仓库是按照一定的数据结果&#xff08;数据结构是指数据的组织形式或数据之间的联系&#xff09;来组织、存储的、我们可以通…

zoj 2526(一道很好的最短路应用题)

题目链接&#xff1a;http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId1538 题意&#xff1a;最短路问题&#xff0c;但是要求出最短路的条数&#xff0c;同时要求出所有可能的最短路选择中javabean最多的情况。 思路&#xff1a;求到终点的最短路径用Dijkstra&am…

MySQL常用命令大全

登录MySQL方法 单实例MySQL登录的方法 mysql #刚装完系统无密码情况登录方式&#xff0c;不需要密码 mysql -u root #刚装完系统无密码的情况登录 mysql -uroot -p #这里标准的dba命令行登录 mysql -uroot -poldboy #非脚本里一般不这样用&#xff0c;密码明文会泄露密码…

服务器安全之iptables iptables

服务器安全之iptables 感谢老男孩老师为我们讲解iptables 优化之路 iptables防火墙简介 Netfilter/Iptables&#xff08;以下简称Iptables&#xff09;是unix/linux自带的一款优秀且开放源代码的安全自由的**基于包过滤的防火墙工具**&#xff0c;它的功能十分强大&#xff0…

MC新手入门(三十)------ 逻辑运算符和表达式

游戏设计中提供了三种逻辑运算符&#xff1a; 1&#xff09;&& 与运算 2&#xff09;|| 或运算 3&#xff09; &#xff01;非运算 游戏设计中我们常常要用到上面的逻辑运算&#xff0c;例如&#xff1a;当在双人游戏中都要实现两人同时存活才能过关&#xff0c;…

Nagios 配置及监控

Nagios 监控 在互联网日益发展的今天&#xff0c;监控的重要性已经不言而喻。可能打开一个URL要经过6-7层的处理&#xff0c;如果出了问题而没有监控将很难定位到问题所在。那哪些内容需要监控呢&#xff1f; 1.本地资源 (1) 负载&#xff1a;uptime&#xff1b; (2) CPU&…

SSH 配置

SSH 批量管理 SSH介绍 SSH是Secure Shell Protocol的简写&#xff0c;由IETF网络工作小组&#xff08;Network working Group&#xff09;指定&#xff1b;在进行数据传输之前&#xff0c;SSH先对联机数据包通过加密技术进行加密处理&#xff0c;加密后在进行数据传输。确保了传…

服务器重启导致无法启动MySQL

今天服务器受到DDOS攻击&#xff0c;笔者脑残重启了一下服务器。结果造成MySQL服务器无法启动mysql日志见下图。160803 17:43:47 mysqld_safe Starting mysqld daemon with databases from /application/mysql/data160803 17:43:47 [Note] /application/mysql/bin/mysqld (mysq…

架构师之DNS实战

架构师 DNS实战 老男孩教育 DNS简介 1. DNS的出现及演化 网络出现的早起是使用IP地址通讯的&#xff0c;那是就几台主机通讯。但是随着接入网络主机的增多&#xff0c;这种数字标识的地址非常不便于记忆&#xff0c;UNIX上就出现了建立一个叫做hosts的文件&#xff08;Linux和W…

打包jar文件后的spring部署及hibernate自动建表经验总结

楔子 用springhibernate做一个服务器运行程序&#xff0c;在部署到服务器时&#xff08;打包成jar&#xff0c;在window server2008下运行&#xff09;&#xff0c;出现了以下两个纠结问题&#xff1a; 1. 加载不了Spring容器 2. hibernate.hbm2ddl.auto 到了服务器不能自动建表…

我是一个线程 [转]

我是一个线程&#xff0c;我一出生就被编了个号&#xff1a;0x3704&#xff0c;然后被领到一个昏暗的屋子里&#xff0c;在这里我发现了很多和我一模一样的同伴。 我身边的同伴0x6900 待的时间比较长&#xff0c;他带着沧桑的口气对我说&#xff1a;“我们线程的宿命就是处理包…

自动化运维之–Cobbler

Cobbler 自动化 Cobbler简介 Cobbler是一个快速网络安装linux的服务&#xff0c;而且在经过调整也可以支持网络安装windows。该工具使用python开发&#xff0c;小巧轻便&#xff08;才15k行python代码&#xff09;&#xff0c;使用简单的命令即可完成PXE网络安装环境的配置&…

开源jumpserver 堡垒机搭建

一、环境 CentOS 6.x x86_64 mini service iptables stop 关闭SELinux的方法&#xff1a; 修改/etc/selinux/config文件中的SELINUX”” 为 disabled &#xff0c;然后重启。 如果不想重启系统&#xff0c;使用命令setenforce 0 1.指定yum源 wget -O /etc/yum.repos.d/e…

Shell 变量及函数讲解 [2]

Shell 变量的输入 Shell变量除了可以直接赋值或脚本传参外&#xff0c;还可以使用read命令从标准输入获得&#xff0c;read为bash内置命令&#xff0c;可以通过help read查看帮助【语法格式】read [参数] [变量名]【常用参数】-p prompt&#xff1a;设置提示信息-t timeout&…

java大作业私人管家系统_重庆管家婆软件丨管家婆工贸PRO的E-MES管理详解

其实&#xff0c;ERP和MES在制造操作中扮演着独立而又互补的角色。ERP能将企业所有方面的数据进行实时、可用的全面集成&#xff0c;为管理决策提供高效、准确的业务决策支持;MES则能加强MRP计划的执行&#xff0c;把MRP计划同车间作业现场控制通过执行系统联系起来。这些“现场…

监控体系 [精]

监控体系 zabbix 监控对象&#xff1a;     1. 监控对象的理解&#xff1a;CPU是怎么工作的&#xff0c;原理     2. 监控对象的指标&#xff1a;CPU使用率 CPU负载 CPU个数 上下文切换     3. 确定性能基准线&#xff1a;怎么样才算故障&#xff1f;CPU负载多…

vs 设置起始页不见了_发朋友圈屏蔽爸妈,结果不小心设置成了仅家人可见...场面一发不可收拾哈哈哈哈!...

一提到爸妈的朋友圈&#xff0c;就会想到养生鸡汤&#xff0c;中老年流量谣言&#xff0c;土味表情包而出于保护个人隐私拒绝被爸妈误解而遭受灵魂拷问的考虑很多人选择了两全其美的分组法给家人看到阳光可爱正能量的一面沙雕的一面只展现给沙雕网友们可如果不小心把屏蔽的内容…

KVM 安装

KVM介绍 Kernel-based Virtual Machine的简称&#xff0c;是一个开源的系统虚拟化模块&#xff0c;自Linux 2.6.20之后集成在Linux的各个主要发行版本中。它使用Linux自身的调度器进行管理&#xff0c;所以相对于Xen&#xff0c;其核心源码很少。KVM目前已成为学术界的主流VMM之…

彼聆智能语音机器人_电销行业的人工智能:智能语音电话机器人

随着人工智能的发展&#xff0c;越来越多的机器人出现在我们的日常生活中&#xff0c;用于电话营销公司的自动打电话机器人、快递公司用来送快递的机器人、餐厅里用来上菜的机器人&#xff0c;最近更是有一款会后空翻的机器人。机器人正活跃在各行各业中&#xff0c;代替人类去…