刚刚差点把封装打成装疯......好吧,开始了,ASP.NET中ajax请求的目标大多是webservice和ashx,以及少量指向自己页面的,webservice客户端通用,但是性能差点,ashx挺完美的,性能最快,但这货没写一个业务,就得创建一个文件,这种我也是非常不爽。
ashx的的实现是基于IHttpHandler接口的,这个接口还是挺简单的。
AJAX请求数量会越来越多,我们用一个简单的工厂模式来分流。
public class AjaxHandlerFactory : IHttpHandlerFactory
{
/// <summary>
/// 缓存,用于缓存请求的Ajax实例
/// </summary>
private System.Web.Caching.Cache _cache = HttpContext.Current.Cache;
/// <summary>
/// 用参数类名(ClassName)返回ajax业务类
/// </summary>
/// <param name="strUrlPath"></param>
/// <returns></returns>
private string GetClassName(string strClass)
{
return string.Format("EMS.WebUtility.HttpHandler.Ajax.{0}, EMS.WebUtility", strClass);
}
#region IHttpHandlerFactory 成员
public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
string strClass = context.Request.Params["ClassName"];
if (string.IsNullOrEmpty(strClass)) return null;
string strClassName = GetClassName(strClass);
//优先从缓存中获取实例
object handle = _cache.Get(strClassName);
if (handle != null)
{
return (IHttpHandler)handle;
}
Type t = Type.GetType(strClassName, false, true);
if (t != null)
{
if (t.GetInterface("IHttpHandler", true) != null)
{
return (IHttpHandler)Activator.CreateInstance(t);
}
}
return null;
}
public void ReleaseHandler(IHttpHandler handler)
{
//如果handle不为null,且设置了IsReusable为true,则缓存handle
if (handler != null && handler.IsReusable)
{
string className = handler.GetType().FullName.ToUpper();
_cache.Insert(className, handler, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(0, 10, 0));
}
}
#endregion
}
这里通过参数ClassName来确定具体的业务类,通过反射实例化,同时这个地方做了缓存,
在写一个抽象的基类:
public abstract class AjaxHandler : IHttpHandler
{
/// <summary>
/// You will need to configure this handler in the web.config file of your
/// web and register it with IIS before being able to use it. For more information
/// see the following link: http://go.microsoft.com/?linkid=8101007
/// </summary>
#region IHttpHandler Members
public bool IsReusable
{
// Return false in case your Managed Handler cannot be reused for another request.
// Usually this would be false in case you have some state information preserved per request.
get { return true; }
}
public virtual string ContengType
{
get { return "text/html"; }
}
/// <summary>
/// 输出数据,请继承
/// </summary>
/// <returns></returns>
public abstract string GetBusinessData();
public void ProcessRequest(HttpContext context)
{
context.Response.ContentEncoding = Encoding.UTF8;
context.Response.ContentType = ContengType;
AjaxMappingAttribute.Bind(this, context.Request.Params);
context.Response.Output.Write(GetBusinessData());
context.Response.End();
}
#endregion
}
GetBusinessData()是由具体业务类实现的,业务类需要继承上面这个类:
public class GetPctCode : AjaxHandler
{
[AjaxMapping("name", true)]
public string StreetName { get; set; }
[AjaxMapping("Number", true)]
public string StreetNum { get; set; }
[AjaxMapping("Quandrant", true)]
public string Quandrant { get; set; }
[AjaxMapping("StType", false)]
public string StType { get; set; }
public override string GetBusinessData()
{
string SubDivistion = BLLClasses.EMS_Street.GetStreetPCTCodeByStreetNameAndNum(StreetName, StreetNum, "", Quandrant, StType);
return SubDivistion;
}
}
这里还用到了AjaxMapping特性,他的功能是映射参数的值到业务类的属性中:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class AjaxMappingAttribute : System.Attribute
{
/// <summary>
/// 参数名称
/// </summary>
public string ParamName { get; set; }
/// <summary>
/// 是否必须
/// </summary>
public bool IsRequired { get; set; }
//构造函数
public AjaxMappingAttribute() : this(null, false) { }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="paramName"></param>
/// <param name="isRequired"></param>
public AjaxMappingAttribute(string paramName, bool isRequired)
{
this.ParamName = paramName;
this.IsRequired = isRequired;
}
/// <summary>
/// 绑定参数
/// </summary>
/// <param name="obj"></param>
/// <param name="param"></param>
public static void Bind(object obj, NameValueCollection param)
{
Mappinger.Mapping<AjaxMappingAttribute>(obj, (paramName, mt) =>
{
return param[paramName];
});
}
}
/// <summary>
/// 属性映射,接收的URL参数映射到相关类上标识为MappingAttribute的属性上
/// </summary>
public class Mappinger
{
public static void Mapping<T>(object obj, Func<string, T, string> getParamValue) where T : AjaxMappingAttribute
{
Type t = obj.GetType();
foreach (PropertyInfo pi in t.GetProperties())
{
object[] customerAttributes = pi.GetCustomAttributes(typeof(T), false);
if (customerAttributes.Length == 1)
{
MethodInfo setMethod = pi.GetSetMethod();
if (setMethod != null)
{
T mapping = customerAttributes[0] as T;
//参数名称,如果没有指定参数名称,则默认为属性名称
string paramName = string.IsNullOrEmpty(mapping.ParamName) ? pi.Name : mapping.ParamName;
string paramValue = getParamValue(paramName, mapping);
if (paramValue == null)
{
if (mapping.IsRequired)
{
throw new ArgumentNullException(string.Format("未提供参数{0}的值", paramName));
}
else
{
continue;
}
}
setMethod.Invoke(obj, new object[] { paramValue });
}
else
{
throw new Exception(string.Format("未定义数据{0}的set构造器,无法进行赋值。", pi.Name));
}
}
}
}
}
以上内容大多抄袭了yangrong.g的这篇文章
yangrong.g的请求是用aspx去映射,我打算另一种办法
用ASP.NET Ajax库就知道会有个ScriptManager,客户端会渲染出一个Resources.axd?XXXXXX的请求,这个axd是在项目中不存在的,就是个URL路由,其实ashx也是这样的一个东西,那我在这里入手,把请求都统一到一个AjaxHandler.axd里:
<add verb="*" path="AjaxHandler.axd" type="EMS.WebUtility.HttpHandler.AjaxHandlerFactory, EMS.WebUtility"/>
客户端的请求只要:
$.post("/AjaxHandler.axd?ClassName=GetPctCode",....