跟小D每日学口语

Ajax的一个封装[原创]

刚刚差点把封装打成装疯......好吧,开始了,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",....

 

 

posted @ 2012-04-27 16:52  腐乳  阅读(394)  评论(2编辑  收藏  举报