用httpHandler实现简易ajax框架
时间:2010-10-09 来源:董兴于
前言:
工作中常常用到以前同事写的一个ajax框架,偶尔抽空看看,感觉恩是复杂,于是自己花心思研究了一个比较简单的,使用httpHandler和反射实现的简易ajax框架。帖出此文,以此铭记,好好学习,天天向上……
步骤一:
首先需要一个接受客户端请求的httpHandler服务,我定义为"AjaxHandler",实现接口"IHttpHandler"和"IRequiresSessionState",有关这两个接口,在此不赘述,有兴趣请翻阅MSDN。
实现一个属性"IsReusable" ,代码如下
public bool IsReusable { get { return false; } }
和一个方法"ProcessRequest",用以接受请求。 在这个方法内,我对请求参数头作了如下规定(即Request.Headers):
键 值 含义
InvokeType Ajax 表示请求方式 为 Ajax 请求 目前只支持该请求,有兴趣的朋友可以实现其他的方式
assembly 字符串 表示要请求的服务器方法所在类所在的程序集完全限定名(如:AjaxTest)
space 字符串 表示要请求的服务器方法所在类所在的命名空间(如:Dxy.AjaxTest)
className 字符串 表示要请求的服务器方法所在类的类名称(如:OrderHelper)
methodName 字符串 表示要请求的服务器方法名称(如:GetOrders)
代码如下:
string assembly = request.Headers["assembly"]??""; string space = request.Headers["space"] ?? ""; string className = request.Headers["className"] ?? ""; string methodName = request.Headers["methodName"] ?? ""; //if (assembly == "") throw new Exception("assembly can not be empty."); if (space == "") throw new Exception("namespace can not be empty."); if (className == "") throw new Exception("type can not be empty."); if (methodName == "") throw new Exception("method can not be empty."); Type type = Type.GetType(space + "." + className + "," + assembly); if (type != null) { MethodInfo method = type.GetMethod(methodName); if (method != null) { object[] arguments = null; ParameterInfo[] parms = method.GetParameters(); if (parms.Length>0) { arguments = new object[parms.Length]; for (int i = 0; i < parms.Length; i++) { arguments[i] = Convert.ChangeType(request.Form[i], parms[i].ParameterType); } } /* 判断调用的方法是否静态方法。 * 如果是静态方法,则方法调用不需创建类实例。*/ object inst = method.IsStatic ? null : Activator.CreateInstance(type, true); if (method.ReturnType.Name == "Void") { method.Invoke(inst, arguments); return ""; } else { return System.Web.HttpUtility.UrlEncode(method.Invoke(inst, arguments).ToString()); } } else { throw new Exception("method invoke failed."); } } else { throw new Exception("type invoke failed."); }
整体代码如下:
using System; using System.Web; using System.Web.SessionState; using System.Reflection; namespace AjaxFramework { public class AjaxHandler : IHttpHandler, IRequiresSessionState { #region IHttpHandler 成员 public bool IsReusable { get { return false; } } public void ProcessRequest(HttpContext context) { try { if (context.Request.Headers["InvokeType"] == "Ajax") { context.Response.Write(InvokeMethod(context.Request)); } } catch (Exception ex) { context.Response.Write(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(ex)); } finally { try { context.Response.End(); } catch { } } } #endregion /// <summary> /// 处理ajax请求 /// </summary> /// <param name="request"></param> /// <returns></returns> private string InvokeMethod(HttpRequest request) { string assembly = request.Headers["assembly"]??""; string space = request.Headers["space"] ?? ""; string className = request.Headers["className"] ?? ""; string methodName = request.Headers["methodName"] ?? ""; //if (assembly == "") throw new Exception("assembly can not be empty."); if (space == "") throw new Exception("namespace can not be empty."); if (className == "") throw new Exception("type can not be empty."); if (methodName == "") throw new Exception("method can not be empty."); Type type = Type.GetType(space + "." + className + "," + assembly); if (type != null) { MethodInfo method = type.GetMethod(methodName); if (method != null) { object[] arguments = null; ParameterInfo[] parms = method.GetParameters(); if (parms.Length>0) { arguments = new object[parms.Length]; for (int i = 0; i < parms.Length; i++) { arguments[i] = Convert.ChangeType(request.Form[i], parms[i].ParameterType); } } /* 判断调用的方法是否静态方法。 * 如果是静态方法,则方法调用不需创建类实例。*/ object inst = method.IsStatic ? null : Activator.CreateInstance(type, true); if (method.ReturnType.Name == "Void") { method.Invoke(inst, arguments); return ""; } else { return System.Web.HttpUtility.UrlEncode(method.Invoke(inst, arguments).ToString()); } } else { throw new Exception("method invoke failed."); } } else { throw new Exception("type invoke failed."); } } } }
步骤二:
将配置文件添加节点,用以指向前面定义的"AjaxHandler"
代码如下:
<httpHandlers> <remove verb="*" path="*.asmx"/> <add verb="*" path="*.dxy" validate="false" type="AjaxFramework.AjaxHandler"/> </httpHandlers>
在这里我规定,凡是后缀为".dxy"的请求都指向"AjaxHandler"时间处理程序。
步骤三:
客户端请求脚本。 ajax核心XMLHttpRequest的创建与请求发送脚本。
代码如下:
//XMLHttpRequest ///<summary>创建XMLHttpRequest实例</summary> function CreateAjax() { var xmlHttp; if (window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest(); } else if (window.ActiveXObject) { try { xmlHttp = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { xmlHttp = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) { } } } return xmlHttp; } var onInitf; //开始发送请求事件 var onCompletef; //请求完成事件 var onErrorf; //请求失败事件 ///<summary>向服务器请求数据</summary> ///<param name="assembly">程序集</param> ///<param name="space">命名空间</param> ///<param name="className">类</param> function AjaxRequest(assembly, space, className) { var xmlHttp = CreateAjax(); ///<param name="methodName">方法</param> ///<param name="args">参数数组</param> ///<param name="onInit">开始发送请求事件</param> ///<param name="onComplete">请求完成事件</param> ///<param name="onError">请求失败事件</param> this.sendRequest = function(methodName, args, onInit, onComplete, onError) { onInitf = onInit; onCompletef = onComplete; onErrorf = onError; xmlHttp.open("POST", "a.dxy"); //以POST方法请求服务器 xmlHttp.setRequestHeader("InvokeType", "Ajax"); xmlHttp.setRequestHeader("assembly", assembly); xmlHttp.setRequestHeader("space", space); xmlHttp.setRequestHeader("className", className); xmlHttp.setRequestHeader("methodName", methodName); xmlHttp.onreadystatechange = function() { switch (xmlHttp.readyState) { case 0: //此处可添加对用户提示的等待信息(如进度条) if (typeof (onInit) == "function") { onInitf(); } break; case 4: //状态==200表示成功 if (xmlHttp.status == 200) { try { onCompletef(parseJson(xmlHttp.responseText)); } catch (e) { onErrorf(e); } } else { var e = parseJson(xmlHttp.responseText); if (e == null) { // e = "{\"Message\":\"服务未找到。\"}"; e = parseJson("{\"Message\":\"服务未找到。\"}"); } onErrorf(e); } break; } } xmlHttp.send(args); this.sendRequest.assembly = assembly; this.sendRequest.space = space; this.sendRequest.className = className; this.sendRequest.methodName = methodName; } } function parseJson(str) { if (typeof (str) == 'string' && str != null) { str = decodeURIComponent(str); try { return eval('(' + str.replace(/\r/g, '\\r').replace(/\n/g, '\\n') + ')'); } catch (e) { return null; } } return null; }
我在其中公开了一个类型AjaxRequest,该类型包含一个实例函数sendRequest,外部调用只需要new一个AjaxRequest对象,然后调用方法传入相应的参数即可。 调用代码如下:
<script language="javascript" type="text/javascript"> function GetOrders() { var ajax = new AjaxRequest("AjaxTest", "Dxy.AjaxTest", "OrderHelper"); var methodName = "GetOrders"; ajax.sendRequest(methodName, null, null, function(data) { var tab = document.createElement("table"); tab.style.width = "400px"; tab.style.height = "300px"; //创建table头部 var hr = tab.insertRow(0); var htd0 = hr.insertCell(0); htd0.innerHTML = "订单编号"; var htd1 = hr.insertCell(1); htd1.innerHTML = "订单日期"; var htd2 = hr.insertCell(2); htd2.innerHTML = "代理商"; var htd3 = hr.insertCell(3); htd3.innerHTML = "金额"; //填充table内容 for (var i = 0; i < data.length; i++) { var row = tab.insertRow(i + 1); var td0 = row.insertCell(0); td0.innerHTML = data[i].OrderID; var td1 = row.insertCell(1); td1.innerHTML = data[i].OrderTime; var td2 = row.insertCell(2); td2.innerHTML = data[i].Proxy; var td3 = row.insertCell(3); td3.innerHTML = data[i].Amount; } document.getElementById("divTest").appendChild(tab); }, function(e) { alert("Ajax错误:" + e.Message); }); } </script>
步骤四:
最后,我写了一个用来测试这个简易ajax框架的服务器后台类和页面。
后台测试类代码如下:
using System; using System.Collections.Generic; namespace Dxy.AjaxTest { public class Order { public string OrderID; public string OrderTime; public string Proxy; public double Amount; } public class OrderHelper { public string GetOrders() { List<Order> list = new List<Order>(); list.Add(new Order() { OrderID=Guid.NewGuid().ToString(), Amount=1111, OrderTime = DateTime.Now.ToString("yyyy-MM-dd"), Proxy="神经病1号" }); list.Add(new Order() { OrderID = Guid.NewGuid().ToString(), Amount = 2222, OrderTime = DateTime.Now.ToString("yyyy-MM-dd"), Proxy = "神经病2号" }); list.Add(new Order() { OrderID = Guid.NewGuid().ToString(), Amount = 3333, OrderTime = DateTime.Now.ToString("yyyy-MM-dd"), Proxy = "神经病3号" }); return new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(list); } } }
页面前台代码如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="AjaxFramework._Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> <style type="text/css"> table { border-top:solid 1px gray; border-left:solid 1px gray; padding:0px; margin:0px; } table td { border-right:solid 1px gray; border-bottom:solid 1px gray; } </style> <script src="JavaScript/Ajax.js" type="text/javascript"></script> <script language="javascript" type="text/javascript"> function GetOrders() { var ajax = new AjaxRequest("AjaxTest", "Dxy.AjaxTest", "OrderHelper"); var methodName = "GetOrders"; ajax.sendRequest(methodName, null, null, function(data) { var tab = document.createElement("table"); tab.style.width = "400px"; tab.style.height = "300px"; //创建table头部 var hr = tab.insertRow(0); var htd0 = hr.insertCell(0); htd0.innerHTML = "订单编号"; var htd1 = hr.insertCell(1); htd1.innerHTML = "订单日期"; var htd2 = hr.insertCell(2); htd2.innerHTML = "代理商"; var htd3 = hr.insertCell(3); htd3.innerHTML = "金额"; //填充table内容 for (var i = 0; i < data.length; i++) { var row = tab.insertRow(i + 1); var td0 = row.insertCell(0); td0.innerHTML = data[i].OrderID; var td1 = row.insertCell(1); td1.innerHTML = data[i].OrderTime; var td2 = row.insertCell(2); td2.innerHTML = data[i].Proxy; var td3 = row.insertCell(3); td3.innerHTML = data[i].Amount; } document.getElementById("divTest").appendChild(tab); }, function(e) { alert("Ajax错误:" + e.Message); }); } </script> </head> <body> <form id="form1" runat="server"> <div id="divTest"> <input type="button" id="btnTest" value="Ajax获取服务器数据" onclick="GetOrders();" /> </div> </form> </body> </html>
页面效果图一:
页面效果图二:
不足之处,请指正。旨在学习。