博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
asp.net webForm也可以这样用Ajax -- My Ajax Framework
阅读量:6183 次
发布时间:2019-06-21

本文共 14212 字,大约阅读时间需要 47 分钟。

       对于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
TestAjaxMethod(int a, string b, float c) { return new List
{ 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("") + 7, errorMessage.indexOf(""))                throw new Error("服务器内部错误:" + errorTitle);            }        }    });}

  

5.       更改Default.aspx.cs的继承页面为AjaxBasePage              

public partial class _Default : AjaxBasePage

6.        主要基类:AjaxBasePage

如下代码:

public class AjaxBasePage : System.Web.UI.Page{    ///     /// 是否是一个ajax请求。    ///     public bool IsAjaxRequest { get; private set; }    ///     ///  如果是Ajax请求,劫持页面生命周期的PreInit的事件,直接返回Response    ///     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);        }    }}

 

        该类重写了PreInit方法,判断请求是否是一个Ajax请求。通过AjaxRequest类接收并处理接收到的请求,提取出一些有效的数据,比如说是否是一个Ajax请求,方法的名字,参数列表(AjaxParameter类)。

        至于AjaxParameter类,内部用的数据结构其实是一个字典,并使用索引来提供对数据的方便访问,提供一个Count属性,方便获取参数的个数。     如下代码:

public class AjaxParameter    {        private IDictionary
m_DictionaryParamsData = new Dictionary
(); ///
/// 返回参数的个数。 /// public int Count { get { return this.m_DictionaryParamsData.Count; } } ///
/// 索引具体参数的值。 /// ///
///
public string this[int index] { get { if (index >= 5 || index < 0) { throw new NotSupportedException("请求方法的参数的个数限制为:0-5"); } return this.m_DictionaryParamsData[index]; } } public AjaxParameter(IDictionary
paramsData) { this.m_DictionaryParamsData = paramsData; } }

  

         AjaxRequest类的设计思路其实是模仿HttpContext设计,HttpContext能够从基础的http请求报文分析出以后处理将要用到的数据(response,request,session,cookie等等)数据,而AjaxRequest通过分析Ajax的Post请求的数据域Data分析出各种以后会用到的数据。如下是该类的代码:

public class AjaxRequest    {        private Dictionary
m_DictionaryParamsData = new Dictionary
(); private AjaxParameter m_AjaxParameter; private int m_Count = 0; #region 属性 ///
/// 是否是一个Ajax请求。 /// public bool IsAjaxRequest { get; private set; } ///
/// 请求的方法名字。 /// public string MethodName { get; private set; } ///
/// 参数数据。 /// 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);            }        }        ///         /// 获取参数数据。        ///         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 parameterData = new List(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)");            }        }        ///         /// 类型转换。支持 String、Boolean、Int32、Int64、UInt32、UInt64、Single、Double、Decimal、DateTime、DateTimeOffset、TimeSpan、Guid        ///         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;        }        ///         /// 结束页面生命周期,同时直接执行应用程序生命周期的EndRequest事件。        ///         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类来封装返回数据。

public class JsonResponse{    public bool IsSuccess { get; set; }    public string Message { get; set; }    public object ResponseData { get; set; }}

         该类最后一个参数即承载了调用方法的返回值,为一个Object类型,也就是说,框架可以支持任何类型的返回值,当然该类型可以被序列化。

7.        回过头来再看Ajax请求,针对返回值可以这样用:

PowerAjax.AsyncAjax('TestAjaxMethod', [1, 2, "333", "sss"], function (SucceessResponse) {                    if (SucceessResponse.IsSuceess) {                        alert("恭喜,该ajax方法调用成功!");                        Process(SucceessResponse.ResponseData); // 处理返回的数据,这里可能需要你自己实现了,因为我无法判断你要返回的是什么东西,这是个Object                    } else {                        alert("这是操作错误奥,不是内部异常,内部异常的抛出会我内部会处理的!");                        alert("错误信息:" + SucceessResponse.Message);                    }                });            });

以上是试水的东西,希望各位大牛指正。

转载于:https://www.cnblogs.com/A_ming/archive/2013/03/28/2986949.html

你可能感兴趣的文章
java Future用法和意义一句话击破
查看>>
JavaScript IE9以下浏览器版本升级提示
查看>>
spring事件通知机制
查看>>
j2EE JSP
查看>>
Windows Server 2003服务器上IIS6.0拥有转发PHP的能力/IIS6.0与PHP共用80端口
查看>>
★如何证明自己不是精神病?
查看>>
Unable to satisfy the following requirements
查看>>
vs 2005 添加GDI配置
查看>>
Tensorflow 基本概念
查看>>
linux tomcat 远程debug
查看>>
3.新浪微博Swift项目第三天
查看>>
win32gui.CeateWindow的参数
查看>>
python 迭代的理解
查看>>
angularjs中ng-repeat里面ng-model的使用
查看>>
centos安装elasticsearch2.3.2记录
查看>>
eclipse不加载dropins目录下的cdt等插件问题解决
查看>>
consul安全加固
查看>>
java中实现类似函数指针的功能
查看>>
python for CFD 第四步
查看>>
wsgi-restful-routes详解:
查看>>