前言:
工作中常常用到以前同事写的一个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获取服务器数据" οnclick="GetOrders();" />
</div>
</form>
</body>
</html>
页面效果图一:
页面效果图二:
不足之处,请指正。旨在学习。