asp.net webForm也可以这样用Ajax -- My Ajax Framework
来源:互联网 发布:先锋网络电视破解版 编辑:程序博客网 时间:2024/05/30 23:44
对于.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类
如下代码:
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); } }}
该类重写了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类来封装返回数据。
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); } }); });
- asp.net webForm也可以这样用Ajax -- My Ajax Framework
- asp.net WebForm项目Ajax示例讲解
- ASP.NET Webform 与JQuery Ajax
- asp.net webform 通过ajax取得json数据(一)
- asp.net webform 通过ajax取得json数据(二)
- ASP.NET WebForm 之 Ajax 请求后端处理 概述 ASP.NET 在MVC中的用途非常广泛,操作起来也非常简单。前台请求异步请求 Controlle
- ASP.NET AJAX Client Framework 源码追踪
- vs. 2005也可以使用web application project, 如何把asp.net ajax特性加入呢?
- Asp.net Ajax:我可以用javascript做些什么?
- Asp.net Ajax:我可以用javascript做些什么?
- Asp.net Ajax:我可以用javascript做些什么?
- 不用asp.net MVC,用WebForm照样可以实现MVC
- Welcome to my comparison of AJAX frameworks for ASP.NET
- Advanced ASP.NET AJAX Server Controls For .NET Framework 3.5
- WebForm、WinForm、Win32、asp.net、C#、.NET Framework和.net
- [转]ASP.NET AJAX client-side framework failed to load
- 这样用也可以的!
- AJAX / AJAX框架 / AJAX.NET (Professional) / ASP.NET AJAX 概念
- asp.net常用插件
- 如何使用cocos2dx 制作一个多向滚屏坦克类射击游戏-第一部分
- hdu1062——Text Reverse
- Form持久化
- Javascript执行效率小结
- asp.net webForm也可以这样用Ajax -- My Ajax Framework
- 尼玛,罗永浩
- MyEclipse快捷键设置
- CString转char*字符串
- CKEditer实现插入图片的功能
- Min_Cut stoerwagner算法
- 视图、索引、存储过程 、触发器、游标及事务
- 学习点滴笔记
- Compile Linux Kernel on Ubuntu 12.04 LTS