asp.net webForm也可以这样用Ajax -- My Ajax Framework [全屏看文]
对于asp.net WebForm项目,进行Ajax操作大概有三种方式:web服务(.asmx文件) , 一般处理程序(.ashx)和 一些Ajax控件。
对于.net提供的ajax控件,暂且不说,只说另外两种方式,都需要引入额外的代码文件对Ajax进行操作(asmx和ashx,且web服务还要引入一个cs文件与之对应),假如要对Example.aspx这个页面添加一些自定义的Ajax操作,并且这些Ajax操作并不会在别的页面上用到,如此不得不引入额外的代码文件完成这个操作,假如这个Ajax操作很简单,只需要一个简单的函数就可以执行,那岂不是很麻烦的过程吗?如此一来,随着项目中Ajax操作的增多,ashx和asmx文件都会随着时间的增长而增长,项目的维护也会随之加倍。为什么我们不能把Ajax操作的后台代码直接放在Example.aspx对应的Example.aspx.cs文件里 ? 如果能这样做,以上两种烦恼都会迎刃而解,不是吗?
于是,按照以上思路,实现了如下Ajax框架。先来看这个框架的实现机制:
上图是自己画的一个缩减版IIS接收到一个aspx请求的HttpApplication管线和asp.net Page在执行ProcessRequest()方法中的页面生命周期的部分事件。Page本身是继承自IHttpHandler接口,IHttpHandler提供了一个重要的约束方法ProcessRequest,该方法是对接收到的信息(HttpContext)进行具体的处理同样,一般处理程序和web服务也实现了自己的IHttpHandler,并以此提供一些Ajax服务。具体的操作过程请自行查找MSDN。
原理是在页面生命周期开始的第一个事件PreInit进行一些处理,一旦发现劫持到的请求是一个ajax请求,那么利用C#的反射来调用aspx.cs中定义的方法,执行完方法之后,调用Response.End()方法,调用这个方法会直接跳到管线的EndRequest事件,从而结束请求,这样就无需走一些没有必要的页面生命周期的步骤,从而完成一个Ajax操作。如果发现是一个正常的操作,那么就走正常流程。
下面以一个简单例子说明该Ajax框架的使用:
1. 添加一个解决方案
2. 新建一个 Default.aspx 页面
3. 在Default.aspx.cs页面中创建一个被调用的测试方法:
public List<string> TestAjaxMethod(int a, string b, float c)
{
return new List<string> { a.ToString(), b, c.ToString() };
}
4. 在Default.aspx中写一个Ajax请求
PowerAjax.AsyncAjax(‘TestAjaxMethod’, [1, 2, "333","sss"], function (SucceessResponse) {
// 成功后的代码
});
PowerAjax.js是用Jquery专门为这个框架封装的一个及其简单的JS类库,这个类库中有两个主要的方法:PowerAjax.AsyncAjax和PowerAjax.SyncAjax,一个提供同步操作,一个 提供异步操作,参数有三个:
第一个参数是即将操作在aspx.cs的Ajax方法的名字(用名字反射方法)。
第二个参数是一个以数组形式组成参数列表数据。
第三个参数是操作成功之后执行执行的回调方法,与c#中的委托一个道理。
以下为这个简单JS库的代码:
var PowerAjax = function () { } PowerAjax.__Private = function () { } // 进行异步操作 PowerAjax.AsyncAjax = function (methodName, paramArray, success) { PowerAjax.__Private.Ajax(methodName, paramArray, success, true ); } // 进行的是同步操作 PowerAjax.SyncAjax = function (methodName, paramArray, success) { PowerAjax.__Private.Ajax(methodName, paramArray, success, false ); } PowerAjax.__Private.Ajax = function (methodName, paramArray, success, isAsync) { var data = {}; switch (paramArray.length) { case 0: data = { 'isAjaxRequest' : true , 'MethodName' : methodName }; break ; case 1: data = { 'isAjaxRequest' : true , 'MethodName' : methodName, "param0" : paramArray[0] }; break ; case 2: data = { 'isAjaxRequest' : true , 'MethodName' : methodName, "param0" : paramArray[0], "param1" : paramArray[1] }; break ; case 3: data = { 'isAjaxRequest' : true , 'MethodName' : methodName, "param0" : paramArray[0], "param1" : paramArray[1], "param2" : paramArray[2] }; break ; case 4: data = { 'isAjaxRequest' : true , 'MethodName' : methodName, "param0" : paramArray[0], "param1" : paramArray[1], "param2" : paramArray[2], "param3" : paramArray[3] }; break ; case 5: data = { 'isAjaxRequest' : true , 'MethodName' : methodName, "param0" : paramArray[0], "param1" : paramArray[1], "param2" : paramArray[2], "param3" : paramArray[3], "param4" : paramArray[4] }; break ; } var url = document.location.href; $.ajax({ type: "post" , url: url, data: data, async: isAsync, datatype: "json" , contentType: "application/x-www-form-urlencoded; charset=UTF-8" , success: function (response) { success(response); }, error: function (response) { if (response.status == 500) { var errorMessage = response.responseText; var errorTitle = errorMessage.substring(errorMessage.indexOf( "<title>" ) + 7, errorMessage.indexOf( "</title>" )) throw new Error( "服务器内部错误:" + errorTitle); } } }); } |
5. 更改Default.aspx.cs的继承页面为AjaxBasePage
public partial class _Default : AjaxBasePage
6. 主要基类:AjaxBasePage类
如下代码:
![](https://common.cnblogs.com/images/copycode.gif)
public class AjaxBasePage : System.Web.UI.Page
{
/// <summary>
/// 是否是一个ajax请求。
/// </summary>
public bool IsAjaxRequest { get; private set; } /// <summary>
/// 如果是Ajax请求,劫持页面生命周期的PreInit的事件,直接返回Response
/// </summary>
protected override void OnPreInit(EventArgs e)
{
AjaxRequest ajaxRequest = AjaxRequest.GetInstance(Request.Form);
this.IsAjaxRequest = ajaxRequest.IsAjaxRequest; if (this.IsAjaxRequest)
{
AjaxApplication ajaxApplication = new AjaxApplication(this, ajaxRequest);
ajaxApplication.EndRequest();
}
else
{
// 如果不是Ajax请求,继续执行页面生命周期的剩余事件
base.OnPreInit(e);
}
}
}
![](https://common.cnblogs.com/images/copycode.gif)
该类重写了PreInit方法,判断请求是否是一个Ajax请求。通过AjaxRequest类接收并处理接收到的请求,提取出一些有效的数据,比如说是否是一个Ajax请求,方法的名字,参数列表(AjaxParameter类)。
至于AjaxParameter类,内部用的数据结构其实是一个字典,并使用索引来提供对数据的方便访问,提供一个Count属性,方便获取参数的个数。 如下代码:
public class AjaxParameter { private IDictionary< int , string > m_DictionaryParamsData = new Dictionary< int , string >(); /// <summary> /// 返回参数的个数。 /// </summary> public int Count { get { return this .m_DictionaryParamsData.Count; } } /// <summary> /// 索引具体参数的值。 /// </summary> /// <param name="index"></param> /// <returns></returns> public string this [ int index] { get { if (index >= 5 || index < 0) { throw new NotSupportedException( "请求方法的参数的个数限制为:0-5" ); } return this .m_DictionaryParamsData[index]; } } public AjaxParameter(IDictionary< int , string > paramsData) { this .m_DictionaryParamsData = paramsData; } } |
AjaxRequest类的设计思路其实是模仿HttpContext设计,HttpContext能够从基础的http请求报文分析出以后处理将要用到的数据(response,request,session,cookie等等)数据,而AjaxRequest通过分析Ajax的Post请求的数据域Data分析出各种以后会用到的数据。如下是该类的代码:
public class AjaxRequest { private Dictionary< int , string > m_DictionaryParamsData = new Dictionary< int , string >(); private AjaxParameter m_AjaxParameter; private int m_Count = 0; #region 属性 /// <summary> /// 是否是一个Ajax请求。 /// </summary> public bool IsAjaxRequest { get ; private set ; } /// <summary> /// 请求的方法名字。 /// </summary> public string MethodName { get ; private set ; } /// <summary> /// 参数数据。 /// </summary> public AjaxParameter Parameters { get { return this .m_AjaxParameter; } } #endregion #region 构造函数 private AjaxRequest(NameValueCollection nameValueCollection) { this .IsAjaxRequest = nameValueCollection[ "isAjaxRequest" ] == "true" ; if ( this .IsAjaxRequest) { this .MethodName = nameValueCollection[ "MethodName" ]; foreach ( string value in nameValueCollection) { string formKey = string .Format( "param{0}" , this .m_Count); if (nameValueCollection[formKey] != null ) { this .m_DictionaryParamsData.Add( this .m_Count, nameValueCollection[formKey]); this .m_Count++; } } m_AjaxParameter = new AjaxParameter( this .m_DictionaryParamsData); } } #endregion #region 实例方法 public static AjaxRequest GetInstance(NameValueCollection nameValueCollection) { return new AjaxRequest(nameValueCollection); } #endregion #region ToString public override string ToString() { return this .MethodName; } #endregion } |
通过分析AjaxRequest的属性IsAjaxRequest可判断是否为Ajax请求,若该请求为一个Ajax请求,那么创建一个AjaxApplication实例,在创建AjaxApplication实例的过程中会利用当前页面和AjaxRequest提供的数据进行实际方法的调用(反射),该类是执行Ajax方法的核心类,其中会判断是否读取的到的方法是一个有效的方法,并判断从JS中AjaxApplication传入的参数类型的有效性,目前只提供对以下13中参数提供支持,如下:
(String、Boolean、Int32、Int64、UInt32、UInt64、Single、Double、Decimal、DateTime、DateTimeOffset、TimeSpan、Guid) |
如果方法中出现非以上类型,将会抛出异常。为了方便Ajax的调试,在JS前段类库中我会对异常进行处理,并抛出Error,Error信息有效的截取了继承自Exception的抛出信息,至于如何获 得更加详细的JS调试信息,以后JS库中可能会做提供更加详细的调用信息,毕竟框架是在改进中进行的。如下是AjaxApplication类的具体代码:
public class AjaxApplication { private AjaxBasePage m_AjaxBasePage; private object m_ResponseData; public AjaxApplication(AjaxBasePage ajaxBasePage, AjaxRequest ajaxRequest) { this .m_AjaxBasePage = ajaxBasePage; Type ajaxBasePageType = ajaxBasePage.GetType(); MethodInfo methodInfo = ajaxBasePageType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance) .FirstOrDefault(item => item.Name == ajaxRequest.MethodName); object [] parameterData = this .GetParameterData(ajaxRequest, methodInfo); if (methodInfo.IsStatic) { this .m_ResponseData = methodInfo.Invoke( null , parameterData); } else { this .m_ResponseData = methodInfo.Invoke(ajaxBasePage, parameterData); } } /// <summary> /// 获取参数数据。 /// </summary> private object [] GetParameterData(AjaxRequest ajaxRequest, MethodInfo methodInfo) { if (methodInfo != null ) { ParameterInfo[] parameterInfos = methodInfo.GetParameters(); if (parameterInfos.Length > 5) { throw new NotSupportedException( "最多支持5个参数" ); } if (parameterInfos.Length > ajaxRequest.Parameters.Count) { throw new ArgumentException( "缺少参数!" ); } List< object > parameterData = new List< object >(parameterInfos.Length); for ( int i = 0; i < parameterInfos.Length; i++) { ParameterInfo parameterInfo = parameterInfos[i]; string paramValue = ajaxRequest.Parameters[i]; try { parameterData.Add(ParseAjaxParameter(paramValue, parameterInfo)); } catch (FormatException) { string format = string .Format( "传入静态方法 {0} 的第 {1} 个(从0开始计数)参数类型不匹配,应该为 {2} 类型 请检查!" , methodInfo.Name, i, parameterInfo.ParameterType.Name); throw new FormatException(format); } } return parameterData.ToArray(); } else { throw new InvalidOperationException( "没有发现此方法,请检查该方法签名(方法必须为public)" ); } } /// <summary> /// 类型转换。支持 String、Boolean、Int32、Int64、UInt32、UInt64、Single、Double、Decimal、DateTime、DateTimeOffset、TimeSpan、Guid /// </summary> private object ParseAjaxParameter( string ajaxParameterValue, ParameterInfo parameterInfo) { object obj; if (parameterInfo.ParameterType == typeof (String)) { obj = ajaxParameterValue; } else if (parameterInfo.ParameterType == typeof (Boolean)) { obj = bool .Parse(ajaxParameterValue); } else if (parameterInfo.ParameterType == typeof (Int32)) { obj = Int32.Parse(ajaxParameterValue); } else if (parameterInfo.ParameterType == typeof (UInt32)) { obj = UInt32.Parse(ajaxParameterValue); } else if (parameterInfo.ParameterType == typeof (UInt64)) { obj = UInt64.Parse(ajaxParameterValue); } else if (parameterInfo.ParameterType == typeof (Single)) { obj = Single.Parse(ajaxParameterValue); } else if (parameterInfo.ParameterType == typeof (Double)) { obj = Double.Parse(ajaxParameterValue); } else if (parameterInfo.ParameterType == typeof (Decimal)) { obj = Decimal.Parse(ajaxParameterValue); } else if (parameterInfo.ParameterType == typeof (DateTime)) { obj = DateTime.Parse(ajaxParameterValue); } else if (parameterInfo.ParameterType == typeof (DateTimeOffset)) { obj = DateTimeOffset.Parse(ajaxParameterValue); } else if (parameterInfo.ParameterType == typeof (TimeSpan)) { obj = TimeSpan.Parse(ajaxParameterValue); } else if (parameterInfo.ParameterType == typeof (Guid)) { obj = Guid.Parse(ajaxParameterValue); } else { throw new NotSupportedException( "方法参数类型不支持!" ); } return obj; } /// <summary> /// 结束页面生命周期,同时直接执行应用程序生命周期的EndRequest事件。 /// </summary> public void EndRequest() { HttpResponse response = this .m_AjaxBasePage.Page.Response; response.ContentType = "application/json" ; response.Clear(); JavaScriptSerializer jsonSerializer2 = new JavaScriptSerializer(); response.Write(jsonSerializer2.Serialize( new JsonResponse { IsSuccess = true , Message = "处理成功" , ResponseData = this .m_ResponseData })); response.End(); } } |
当初始化了一个AjaxApplication实例后, 可以调用该实例的EndRequest()方法,来结束Ajax请求。该方法内部最后调用Response.End()方法来结束页面生命周期和大部分管线事件。
并用JsonResponse类来封装返回数据。
![](https://common.cnblogs.com/images/copycode.gif)
public class JsonResponse
{
public bool IsSuccess { get; set; }
public string Message { get; set; }
public object ResponseData { get; set; }
}
![](https://common.cnblogs.com/images/copycode.gif)
该类最后一个参数即承载了调用方法的返回值,为一个Object类型,也就是说,框架可以支持任何类型的返回值,当然该类型可以被序列化。
7. 回过头来再看Ajax请求,针对返回值可以这样用:
![](https://common.cnblogs.com/images/copycode.gif)
PowerAjax.AsyncAjax('TestAjaxMethod', [1, 2, "333", "sss"], function (SucceessResponse) {
if (SucceessResponse.IsSuceess) {
alert("恭喜,该ajax方法调用成功!");
Process(SucceessResponse.ResponseData); // 处理返回的数据,这里可能需要你自己实现了,因为我无法判断你要返回的是什么东西,这是个Object
} else {
alert("这是操作错误奥,不是内部异常,内部异常的抛出会我内部会处理的!");
alert("错误信息:" + SucceessResponse.Message);
}
});
});
![](https://common.cnblogs.com/images/copycode.gif)
以上是试水的东西,希望各位大牛指正。
asp.net webForm也可以这样用Ajax -- My Ajax Framework [全屏看文]的更多相关文章
- ASP.NET WebForm 之 Ajax 请求后端处理
概述 ASP.NET MVC中的异步用途非常广泛,操作起来也非常简单.前台请求异步请求 Controller下的Action 方法,后端返回ActionResult 即可.但是在ASP.NET Web ...
- ASP.NET WebForm Ajax请求Handler的经验
ajax代码 $.ajax({ type: "GET", url: "/AjaxHandler/GetPluginCode.ashx", data: " ...
- ASP.Net WebForm温故知新学习笔记:一、aspx与服务器控件探秘
开篇:毫无疑问,ASP.Net WebForm是微软推出的一个跨时代的Web开发模式,它将WinForm开发模式的快捷便利的优点移植到了Web开发上,我们只要学会三步:拖控件→设属性→绑事件,便可以行 ...
- 【Ext.Net学习笔记】01:在ASP.NET WebForm中使用Ext.Net
Ext.NET是基于跨浏览器的ExtJS库和.NET Framework的一套支持ASP.NET AJAX的开源Web控件,包含有丰富的Ajax运用,其前身是Coolite. 下载地址:http:// ...
- ASP.Net WebForm学习笔记:一、aspx与服务器控件探秘
作者:周旭龙 出处:http://edisonchou.cnblogs.com 开篇:毫无疑问,ASP.Net WebForm是微软推出的一个跨时代的Web开发模式,它将WinForm开发模式的快捷便 ...
- 圖片裁剪大頭貼功能 - ASP.NET WebForm + jQuery + imgAreaSelect
系統操作環境: ASP.NET WebForm .NET Framework 4.0 (C#) jQuery 1.7.1 imgAreaSelect 0.9.8 目錄結構: 與之前使用ASP.NET ...
- 利用Bootstrap+Avalonjs+EntityFramework 开发ASP.NET WebForm应用程序(上)
本文将介绍如何利用Bootstrap+Avalonjs+EntityFramework 开发ASP.NET WebForm应用程序,分为上下两篇.上篇主要介绍实现,下篇主要介绍界面. 打开Visual ...
- .net mvc 站点自带简易SSL加密传输 Word报告自动生成(例如 导出数据库结构) 微信小程序:动画(Animation) SignalR 设计理念(一) ASP.NET -- WebForm -- ViewState ASP.NET -- 一般处理程序ashx 常用到的一些js方法,记录一下 CryptoJS与C#AES加解密互转
.net mvc 站点自带简易SSL加密传输 因项目需要,传输数据需要加密,因此有了一些经验,现简易抽出来分享! 请求:前端cryptojs用rsa/aes 或 rsa/des加密,后端.net ...
- asp.net webform 打造私人后台管理系统(附源码)
系统简介 git地址:https://github.com/qingfengjun/XSSystem 不少人让我做公司的网站,要求不多,但是需要有一个后台系统,所以就有了开发的动力.也想做个系统自己学 ...
随机推荐
- 「BZOJ 1831」「AHOI 2008」逆序对「贪心」
题意 给定一个长度为\(n\),值域为\([1,k]\),某些位置不确定的数组,求最小的逆序对.\(n\leq 10^4, k \leq 100\) 题解 这题有人用前缀和优化\(dp\)过了,但是这 ...
- B - Pie (二分)
My birthday is coming up and traditionally I'm serving pie. Not just one pie, no, I have a number N ...
- [linux]阿里云主机的免密码登陆安全SSH配置与思考
公司服务器使用的第三方云端服务,即阿里云,而本地需要经常去登录到服务器做相应的配置工作,鉴于此,每次登录都要使用密码是比较烦躁的,本着极速思想,我们需要配置我们的免登陆. 一 理论概述 SSH介绍 S ...
- Python翻译器
import urllib.request import urllib.parse import json content='有了我,翻译再也不是问题啦' print(content) while c ...
- flink学习笔记-快速生成Flink项目
说明:本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKh ...
- opencv-图片合成视频
无论视频的合成还是分解我们都需要进行解码器或者是编码器(因为视频不是一帧一帧进行存储的,而是进行过压缩编码.) import cv2 img = cv2.imread('image1.jpg') im ...
- CSS+jQuery实现轮播
CSS+jQuery实现轮播 CSS jQuery 前端 实现功能: 自动轮播: 鼠标放在上面停止轮播: 鼠标放在上面显示左右切换的按钮: 鼠标放在小圆圈上显示对应的图片: 轮播效果图 style. ...
- php中静态绑定
自 PHP 5.3.0 起,PHP 增加了一个叫做后期静态绑定的功能,用于在继承范围内引用静态调用的类. 虽然也可以调用非静态方法,但是不会在运行时绑定. static 不再只是简单的静态修饰关键字. ...
- Appium——appium之mac环境安装
一.安装brew:Homebrew是一款Mac OS平台下的软件包管理工具执行:/usr/bin/ruby -e "$(curl -fsSL https://raw.githubuserco ...
- jinkens 'python' 不是内部或外部命令,也不是可运行的程序 或批处理文件。
jinkens执行构建时报错 解决方法,就是指定路径.python的安装目录和被执行文件的的目录