国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

編寫輕量ajax組件03-實現(xiàn)(附源碼)

2019-11-14 13:48:48
字體:
供稿:網(wǎng)友

前言

  通過前兩篇的介紹,我們知道要執(zhí)行頁面對象的方法,核心就是反射,是從請求獲取參數(shù)并執(zhí)行指定方法的過程。實際上這和asp.net mvc框架的核心思想很類似,它會解析url,從中獲取controller和action名稱,然后激活controller對象,從請求獲取action參數(shù)并執(zhí)action。在web form平臺上,我們把方法寫在.aspx.cs中,要實現(xiàn)的就是在頁面對象還未生成的情況下,執(zhí)行指定的方法,然后返回結(jié)果。

  我們先看實現(xiàn)后幾個調(diào)用例子,這些功能也可以組合使用:

        [AjaxMethod]        public void Test1(int index)        {            //簡單調(diào)用        }        [AjaxMethod]        public string Test2(Test test)        {            return "參數(shù)為一個Test實例";        }        [AjaxMethod(OutputCache = 20)]        public string Test3(int index)        {            return "輸出結(jié)果緩存20秒";        }        [AjaxMethod(ServerCache = 20)]        public string Test4()        {            return "在服務(wù)端緩存20秒";        }        [AjaxMethod(sessionState=SessionState.None)]        public void Test5()        {           //Session未被加載        }        [AjaxMethod(SessionState = SessionState.ReadOnly)]        public void Test6()        {            //Session只能讀不能寫        }        [AjaxMethod(SessionState = SessionState.ReadWrite)]        public void Test7()        {            //Session可以讀寫        }        [AjaxMethod(IsAsync = true)]        public void Test8()        {            //異步調(diào)用        }   

  前面兩篇我們已經(jīng)熟悉基本的執(zhí)行流程,現(xiàn)在直接進入主題。

Ajax約定

  通常現(xiàn)在主流瀏覽器在使用ajax發(fā)送異步請求時,請求頭都會帶上一個:X-Requested-With:xmlHttPRequest 的標(biāo)記。我們也可以直接通過這個標(biāo)記來判斷是不是ajax請求,不過項目中可能有用其它的組件,為了不相互影響,我們加入一個自定義的請求頭。這里為:

    internal static class AjaxConfig    {        /// <summary>        /// 請求頭Ajax標(biāo)記鍵        /// </summary>        public const string Key = "AjaxFlag";        /// <summary>        /// 請求頭Ajax標(biāo)記值        /// </summary>        public const string Value = "XHR";        /// <summary>        /// 請求頭Ajax方法標(biāo)記        /// </summary>        public const string MethodName = "";    }
View Code

  意思是如果http 的請求頭包含一個 AjaxFlag : XHR,就是我們要處理的。另外http header的MethodName就表示我們要執(zhí)行的方法的名稱。

AjaxMethodAttribute標(biāo)記屬性

  標(biāo)記屬性是給反射用的,在這里定義我們需要的一些功能。我們希望有:

  1. 可以配置Session狀態(tài)

  2. 支持異步Handler

  3. 支持Get緩存

  4. 支持服務(wù)端緩存

  定義如下,用AttributeUsag標(biāo)記該標(biāo)記只能用于方法上。

    /// <summary>    /// ajax方法標(biāo)記屬性    /// </summary>    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]    public class AjaxMethodAttribute : Attribute    {        public AjaxMethodAttribute()        {                   }        private SessionState _sessionState = SessionState.None;        private int _outputCache = 0;        private int _serverCache = 0;        private ContentType _contentType = ContentType.Plain;        private bool _isUseAsync = false;        /// <summary>        /// session狀態(tài)        /// </summary>        public SessionState SessionState         {            get { return _sessionState; }            set { _sessionState = value; }        }        /// <summary>        /// 客戶端緩存時間,以秒為單位。該標(biāo)記只對get請求有效        /// </summary>        public int OutputCache         {            get { return _outputCache; }            set { _outputCache = value; }        }        /// <summary>        /// 服務(wù)端緩存時間,以秒為單位        /// </summary>        public int ServerCache         {            get { return _serverCache; }            set { _serverCache = value; }        }                /// <summary>        /// 輸出類型(默認為text/plain)        /// </summary>        public ContentType ContentType         {            get { return _contentType; }            set { _contentType = value; }        }        /// <summary>        /// 使用啟用異步處理        /// </summary>        public bool IsAsync         {            get { return _isUseAsync; }            set { _isUseAsync = value; }        }    }    /// <summary>    /// Session狀態(tài)    /// </summary>    public enum SessionState    {        None,        ReadOnly,        ReadWrite            }    /// <summary>    /// 輸出內(nèi)容類型    /// </summary>    public enum ContentType    {        Plain,        Html,        XML,        javascript,        JSON    }
View Code

各種處理程序和AjaxHandlerFactory

  按照上一篇的說法,具體的Handler主要分為兩類,異步和非異步;這兩類下,對于Session的狀態(tài)又有3三種,不支持、只支持讀(實現(xiàn)IReadOnlySessionState接口)、支持讀寫(實現(xiàn)IRequiresSessionState接口)。IReadOnlySessionState和IRequiresSessionState都只是標(biāo)記接口(無任何方法,其實應(yīng)該用標(biāo)記屬性實現(xiàn)比較合理)。異步的Handler需要實現(xiàn)IHttpAsyncHandler接口,該接口又實現(xiàn)了IHttpHandler。Handler的ProcessRequest方法(或BeginProcessRequest)就是我們要執(zhí)行方法的地方。定義如下:

  非異步狀態(tài)的Handler:

    //不支持Session    internal class SyncAjaxHandler : IHttpHandler    {        private Page _page;        private CacheMethodInfo _cacheMethodInfo;        internal SyncAjaxHandler(Page page, CacheMethodInfo cacheMethodInfo)        {            _page = page;            _cacheMethodInfo = cacheMethodInfo;        }        public void ProcessRequest(HttpContext context)        {            //執(zhí)行方法(下面詳細介紹)            Executor.Execute(_page, context, _cacheMethodInfo);        }        public bool IsReusable        {            get { return false; }        }        public static SyncAjaxHandler CreateHandler(Page page, CacheMethodInfo cacheMethodInfo, SessionState state)        {            switch (state)            {                case SessionState.ReadOnly:                    return new SyncAjaxSessionReadOnlyHandler(page, cacheMethodInfo);                case SessionState.ReadWrite:                    return new SyncAjaxSessionHandler(page, cacheMethodInfo);                default:                    return new SyncAjaxHandler(page, cacheMethodInfo);            }        }    }    //支持只讀Session    internal class SyncAjaxSessionReadOnlyHandler : SyncAjaxHandler, IReadOnlySessionState    {        internal SyncAjaxSessionReadOnlyHandler(Page page, CacheMethodInfo cacheMethodInfo)            : base(page, cacheMethodInfo)        {        }    }    //支持讀寫Session    internal class SyncAjaxSessionHandler : SyncAjaxHandler, IRequiresSessionState    {        internal SyncAjaxSessionHandler(Page page, CacheMethodInfo cacheMethodInfo)            : base(page, cacheMethodInfo)        {        }    }  
View Code

  異步狀態(tài)的Handler:

    //不支持Session    internal class ASyncAjaxHandler : IHttpAsyncHandler, IHttpHandler    {        private Page _page;        private CacheMethodInfo _cacheMethodInfo;        internal ASyncAjaxHandler(Page page, CacheMethodInfo cacheMethodInfo)        {            _page = page;            _cacheMethodInfo = cacheMethodInfo;        }        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)        {            //執(zhí)行方法(下面詳細介紹)            Action<Page, HttpContext, CacheMethodInfo> action = new Action<Page, HttpContext, CacheMethodInfo>(Executor.Execute);            IAsyncResult result = action.BeginInvoke(_page, context, _cacheMethodInfo, cb, action);            return result;        }        public void EndProcessRequest(IAsyncResult result)        {            Action<Page, HttpContext, CacheMethodInfo> action = result.AsyncState as Action<Page, HttpContext, CacheMethodInfo>;            action.EndInvoke(result);        }        public void ProcessRequest(HttpContext context)        {            throw new NotImplementedException();        }        public bool IsReusable        {            get { return false; }        }        public static ASyncAjaxHandler CreateHandler(Page page, CacheMethodInfo cacheMethodInfo, SessionState state)        {            switch (state)            {                case SessionState.ReadOnly:                    return new ASyncAjaxSessionReadOnlyHandler(page, cacheMethodInfo);                case SessionState.ReadWrite:                    return new ASyncAjaxSessionHandler(page, cacheMethodInfo);                default:                    return new ASyncAjaxHandler(page, cacheMethodInfo);            }        }    }    //支持只讀Session    internal class ASyncAjaxSessionReadOnlyHandler : ASyncAjaxHandler, IReadOnlySessionState    {        internal ASyncAjaxSessionReadOnlyHandler(Page page, CacheMethodInfo cacheMethodInfo)            : base(page, cacheMethodInfo)        {        }    }    //支持讀寫Session    internal class ASyncAjaxSessionHandler : ASyncAjaxHandler, IRequiresSessionState    {        internal ASyncAjaxSessionHandler(Page page, CacheMethodInfo cacheMethodInfo)            : base(page, cacheMethodInfo)        {        }    }    
View Code

  AjaxHandlerFactory實現(xiàn)了IHandlerFactory接口,用來根據(jù)請求生成具體的Handler,它需要在web.config進行注冊使用。AjaxHandlerFactory的GetHandler是我們攔截請求的第一步。通過請求頭的AjaxFlag:XHR來判斷是否需要我們處理,如果是,則創(chuàng)建一個Handler,否則按照普通的方式進行。由于我們的方法是寫在.aspx.cs內(nèi)的,我們的請求是.aspx后綴的,也就是頁面(Page,實現(xiàn)了IHttpHandler)類型,Page是通過PageHandlerFactory創(chuàng)建的,PageHandlerFactory也實現(xiàn)了IHandlerFactory接口,表示它是用來創(chuàng)建處理程序的。所以我們需要用PageHandlerFactory來創(chuàng)建一個IHttpHandler,不過PageHandlerFactory的構(gòu)造函數(shù)是protected internal類型的,我們無法直接new一個,所以需要通過一個CommonPageHandlerFactory繼承它來實現(xiàn)。

  通過PageHandlerFactory獲得Page后,結(jié)合方法名稱,我們就可以反射獲取AjaxMethodAttribute標(biāo)記屬性了。然后根據(jù)它的相關(guān)屬性生成具體的Handler。具體代碼如下:

    internal class CommonPageHandlerFactory : PageHandlerFactory { }    internal class AjaxHandlerFactory : IHttpHandlerFactory    {        public void ReleaseHandler(IHttpHandler handler)        {        }        public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)        {            HttpRequest request = context.Request;            if (string.Compare(request.Headers[AjaxConfig.Key], AjaxConfig.Value, true) == 0)            {                //檢查函數(shù)標(biāo)記                string methodName = request.Headers[AjaxConfig.MethodName];                if (methodName.IsNullOrEmpty())                {                    Executor.EndCurrentRequest(context, "方法名稱未正確指定!");                    return null;                }                try                {                                        CommonPageHandlerFactory ajaxPageHandler = new CommonPageHandlerFactory();                    IHttpHandler handler = ajaxPageHandler.GetHandler(context, requestType, url, pathTranslated);                    Page page = handler as Page;                    if (page == null)                    {                        Executor.EndCurrentRequest(context, "處理程序類型必須是aspx頁面!");                        return null;                    }                    return GetHandler(page, methodName, context);                }                catch                {                    Executor.EndCurrentRequest(context, url + " 不存在!");                    return null;                }            }            if (url.EndsWith(".aspx", StringComparison.CurrentCultureIgnoreCase))            {                CommonPageHandlerFactory orgPageHandler = new CommonPageHandlerFactory();                return orgPageHandler.GetHandler(context, requestType, url, pathTranslated);            }            return null;        }        /// <summary>        /// 獲取自定義處理程序        /// </summary>        /// <param name="page">處理頁面</param>        /// <param name="methodName">處理方法</param>        /// <param name="context">當(dāng)前請求</param>        private IHttpHandler GetHandler(Page page, string methodName, HttpContext context)        {            //根據(jù)Page和MethodName進行反射,獲取標(biāo)記屬性(下面詳細介紹)            CacheMethodInfo methodInfo = Executor.GetDelegateInfo(page, methodName);            if (methodInfo == null)            {                Executor.EndCurrentRequest(context, "找不到指定的Ajax方法!");                return null;            }            AjaxMethodAttribute attribute = methodInfo.AjaxMethodAttribute;            if (attribute.ServerCache > 0)            {                //先查找緩存                object data = CacheHelper.TryGetCache(context);                if (data != null)                {                    Executor.EndCurrentRequest(context, data);                    return null;                }            }            if (attribute.IsAsync)            {                //異步處理程序                return ASyncAjaxHandler.CreateHandler(page, methodInfo, attribute.SessionState);            }            return SyncAjaxHandler.CreateHandler(page, methodInfo, attribute.SessionState);        }    }
View Code

  上面的CacheMethodInfo是用于緩存調(diào)用方法的相關(guān)信息的,第一篇我們有提到過優(yōu)化緩存的一些方法,其中就包括緩存+委托。但這里我們并不直接緩存方法的MethodInfo,因為緩存MethodInfo的話,需要通過Invoke去執(zhí)行,這樣的效率比較低。這里我緩存的是方法的委托,該委托的簽名為:Func<object, object[], object>,該委托的返回值為object類型,表示可以返回任意的類型(我們可以在組件內(nèi)部進行處理,例如如果是引用類型(非string),就將其序列化為json,但這里并沒有實現(xiàn))。該委托接收兩個參數(shù),第一個參數(shù)是方法所屬的對象,如果是靜態(tài)方法就是null;第二個參數(shù)是方法的參數(shù),定義為object[]表示可以接收任意類型的參數(shù)。通過委托執(zhí)行方法,與直接調(diào)用方法的效率差別就不是很大(對委托不熟悉的朋友可以參見:委托)。CacheMethodInfo的定義如下:

    /// <summary>    /// 緩存方法信息        /// </summary>    sealed class CacheMethodInfo    {        /// <summary>        /// 方法名稱        /// </summary>        public string MethodName { get; set; }        /// <summary>        /// 方法委托        /// </summary>        public Func<object, object[], object> Func { get; set; }        /// <summary>        /// 方法參數(shù)        /// </summary>        public ParameterInfo[] Parameters { get; set; }        /// <summary>        /// Ajax標(biāo)記屬性        /// </summary>        public AjaxMethodAttribute AjaxMethodAttribute { get; set; }    }
View Code

核心方法

1. Eexcutor.GetDelegateInfo 獲取方法相關(guān)信息

  該方法用于遍歷頁面類,獲取所有AjaxMethodAttribute標(biāo)記的方法信息,生成一個CacheMethodInfo對象,包括標(biāo)記信息、方法名稱、參數(shù)信息,以及最重要的方法委托。該對象會緩存在一個哈希表中,下次獲取時,直接從內(nèi)存獲得。

        /// <summary>        /// 獲取頁面標(biāo)記方法信息        /// </summary>        /// <param name="page">頁面對象</param>        /// <param name="methodName">方法名稱</param>        internal static CacheMethodInfo GetDelegateInfo(Page page, string methodName)        {            if (page == null)            {                throw new ArgumentNullException("page");            }            Type type = page.GetType();            //ajaxDelegateTable是一個Hashtable            Dictionary<string, CacheMethodInfo> dic = ajaxDelegateTable[type.AssemblyQualifiedName] as Dictionary<string, CacheMethodInfo>;            if (dic == null)            {                dic = new Dictionary<string, CacheMethodInfo>();                //遍歷頁面的所有MethodInfo                IEnumerable<CacheMethodInfo> infos = (from m in type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)                                                      let ca = m.GetCustomAttributes(typeof(AjaxMethodAttribute), false).FirstOrDefault()                                                      where ca != null                                                      select new CacheMethodInfo                                                      {                                                          //方法標(biāo)記屬性                                                          AjaxMethodAttribute = ca as AjaxMethodAttribute,                                                          //方法名稱                                                          MethodName = m.Name,                                                          //方法參數(shù)信息                                                          Parameters = m.GetParameters()                                                      });                if (infos.IsNullOrEmpty())                {                    return null;                }                                    for (int i = 0, length = infos.Count(); i < length; i++)                {                                        CacheMethodInfo cacheMethodInfo = infos.ElementAt(i);                                        string name = cacheMethodInfo.MethodName;                    MethodInfo methodInfo = type.GetMethod(name);                    if (!dic.ContainsKey(name))                    {                                                //根據(jù)MethodInfo獲取方法委托                        cacheMethodInfo.Func = ReflectionUtil.GetMethodDelegate(methodInfo);                        dic.Add(name, cacheMethodInfo);                    }                }                ajaxDelegateTable[type.AssemblyQualifiedName] = dic;            }            CacheMethodInfo currentMethodInfo = null;            dic.TryGetValue(methodName, out currentMethodInfo);            return currentMethodInfo;                    }
View Code

  獲取方法的委托的是通過一個ReflectionUtil獲得的,該類主要用來優(yōu)化反射,它通過Expression,可以將MethodInfo編譯成Func<object,object[],object>委托,為Type編譯一個Func<object>委托,用于創(chuàng)建實例對象。

  通過Expression優(yōu)化反射

  Expression(表達式樹)允許我們將代碼邏輯以表達式的形式存儲在樹狀結(jié)構(gòu)里,然后在運行時去動態(tài)解析,實現(xiàn)動態(tài)編輯和執(zhí)行代碼。熟悉ORM框架的朋友對Expression肯定很熟悉,因為大部分方法都有一個Expression<TDelegate>類型的參數(shù)。訪問關(guān)系型數(shù)據(jù)庫的本質(zhì)還是sql語句,orm的工作就是為開發(fā)人員屏蔽這個過程,以面向?qū)ο蟮姆绞饺プx寫數(shù)據(jù)庫,而不是自己編寫sql語句。例如,Users.Where(u => u.Age > 18) 就可查詢年齡大于18的用戶。這里不對應(yīng)用在orm的過程進行詳解,下面我們介紹如何用Expression并利用它來生成委托。

  .net定義了許多表達式類型,這些類型都派生自Expression,Expression是一個抽象類,而且是一個工廠類,所有類型的表達式都通過它來創(chuàng)建。如圖:

  先看一個 1 * 2 + 2 例子,我們用表達樹來描述來描述它:

            /*             *  a * b + 2              */            /*            直接操作            int a = 1, b = 2;            int result = a * 2 + 2;            */            /*            通過委托調(diào)用            Func<int, int, int> func = new Func<int, int, int>((a, b) => { return a * b + 2; });            func(1, 2);            */            /*通過Expression調(diào)用*/            //定義兩個參數(shù)            ParameterExpression pe1 = Expression.Parameter(typeof(int), "a");            ParameterExpression pe2 = Expression.Parameter(typeof(int), "b");            //定義一個常量            ConstantExpression constExpression = Expression.Constant(2);                        //參數(shù)數(shù)組            ParameterExpression[] parametersExpression = new ParameterExpression[]{pe1,pe2};            //一個乘法運算            BinaryExpression multiplyExpression = Expression.Multiply(pe1, pe2);            //一個加法運算            BinaryExpression unaryExpression = Expression.Add(multiplyExpression, constExpression);            //將上面的表達式轉(zhuǎn)換為一個委托表達式            LambdaExpression lambdaExpression = Expression.Lambda<Func<int, int, int>>(unaryExpression, parametersExpression);            //將委托編譯成可執(zhí)行代碼            Func<int,int,int> func = lambdaExpression.Compile() as Func<int,int,int>;            Console.WriteLine(func(1, 2));
View Code

  可以看到我們最終將其編譯為一個具體類型的委托了。下面看我們真正用到的方法是如何實現(xiàn)的,代碼如下:

        public static Func<object, object[], object> GetMethodDelegate(MethodInfo methodInfo)        {            if (methodInfo == null)            {                throw new ArgumentNullException("methodInfo");            }            //定義參數(shù)表達式,它表示委托的第一個參數(shù)            ParameterExpression instanceExp = Expression.Parameter(typeof(object), "instance");            //定義參數(shù)表達式,它表示委托的第二個參數(shù)            ParameterExpression paramExp = Expression.Parameter(typeof(object[]), "parameters");            //獲取方法的參數(shù)信息數(shù)組            ParameterInfo[] paramInfos = methodInfo.GetParameters();            //參數(shù)表達式集合            List<Expression> paramExpList = new List<Expression>();            int length = paramInfos.Length;            for (int i = 0; i < length; i++)            {                //獲取paramExp參數(shù)數(shù)組的第i個元素                BinaryExpression valueObj = Expression.ArrayIndex(paramExp, Expression.Constant(i));                //將其轉(zhuǎn)換為與參數(shù)類型一致的類型                UnaryExpression valueCast = Expression.Convert(valueObj, paramInfos[i].ParameterType);                //添加到參數(shù)集合                paramExpList.Add(valueCast);            }                 //方法所屬的實例的表達式,如果為靜態(tài)則為null            UnaryExpression instanceCast = methodInfo.IsStatic ? null : Expression.Convert(instanceExp, methodInfo.ReflectedType);            //表示調(diào)用方法的表達式             MethodCallExpression methodCall = Expression.Call(instanceCast, methodInfo, paramExpList);            //將表達式目錄描述的lambda編譯為可執(zhí)行代碼(委托)            if (methodCall.Type == typeof(void))            {                Expression<Action<object, object[]>> lambda = Expression.Lambda<Action<object, object[]>>(methodCall, instanceExp, paramExp);                Action<object, object[]> action = lambda.Compile();                return (instance, parameters) =>                {                    action(instance, parameters);                    return null;                };            }            else            {                UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));                Expression<Func<object, object[], object>> lambda = Expression.Lambda<Func<object, object[], object>>(castMethodCall, instanceExp, paramExp);                return lambda.Compile();            }        }
View Code

  具體代碼都有注釋解釋,最終我們獲得了一個Func<object,object[],object>類型的委托,它會作為CacheMethodInfo的屬性進行緩存。有興趣測試反射性能的朋友,也不妨去測試對比一下這幾種方式執(zhí)行的效率差別:1.直接執(zhí)行方法 2.Emit 3. 緩存+委托 4.Delegate.DynamicInvoke。

2. Executor.Execute 執(zhí)行委托

  在執(zhí)行委托前,我們需要先從請求獲取參數(shù),映射到方法。參數(shù)可以是簡單的類型,如 string Test(int i,int j); 也可以是一個對象,如 string Test(User user); 如果是 string Test(User user1, User user2) 也行,提交參數(shù)時只需要加上 user1或 user2 前綴即可,例如 user1.Name,user2.Name。這里沒有支持更多的匹配方式,像mvc,它還支持嵌套類型等等,這些可以自己去實現(xiàn)。如果參數(shù)是一個對象,我們可能需要為它的字段進行賦值,也可能為它的屬性進行賦值。這里我們定義一個DataMember,用來表示字段或?qū)傩缘母割悺H纾?/p>

     internal abstract class DataMember    {        public abstract string Name { get; }        public abstract Type MemberType { get; }        public abstract void SetValue(object instance,object value);        public abstract object GetValue(object instance);    }

  接著定義屬性類型PropertyMember和字段類型FieldMember,分別繼承了DataMember。

  PropertyMember定義:

    internal class PropertyMember : DataMember    {        private PropertyInfo property;        public PropertyMember(PropertyInfo property)        {            if (property == null)            {                throw new ArgumentNullException("property");            }            this.property = property;        }        public override void SetValue(object instance, object value)        {            if (instance == null)            {                throw new ArgumentNullException("instance");            }            this.property.SetValue(instance, value, null);        }        public override object GetValue(object instance)        {            if (instance == null)            {                throw new ArgumentNullException("instance");            }            return this.property.GetValue(instance,null);        }        public override string  Name        {            get { return this.property.Name; }        }        public override Type MemberType        {            get { return this.property.PropertyType; }        }    }
View Code

  FieldMember定義:

    internal class FieldMember : DataMember    {        private FieldInfo field;        public FieldMember(FieldInfo field)        {            if (field == null)            {                throw new ArgumentNullException("field");            }            this.field = field;        }        public override void SetValue(object instance, object value)        {            if (instance == null)            {                throw new ArgumentNullException("instance");            }            this.field.SetValue(instance, value);        }        public override object GetValue(object instance)        {            if (instance == null)            {                throw new ArgumentNullException("instance");            }            return this.field.GetValue(instance);        }        public override string  Name        {            get { return this.field.Name;}        }        public override Type MemberType        {            get { return this.field.FieldType; }        }    }
View Code

  定義一個DataMemberManager,用來遍歷Type,獲取所有字段和屬性的,實現(xiàn)如下:

    internal static class DataMemberManager    {        /// <summary>        /// 獲取實例字段/屬性集合        /// </summary>        /// <param name="type">類型</param>        /// <returns></returns>        public static List<DataMember> GetDataMember(Type type)        {            if (type == null)            {                throw new ArgumentNullException("type");            }            IEnumerable<PropertyMember> propertyMembers = from property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)                                                  select new PropertyMember(property);            IEnumerable<FieldMember> fieldMembers = from field in type.GetFields(BindingFlags.Instance | BindingFlags.Public)                                             select new FieldMember(field);            List<DataMember> members = new List<DataMember>();            foreach(var property in propertyMembers)            {                members.Add(property);            }            foreach (var field in fieldMembers)            {                members.Add(field);            }            return members;        }    }
View Code

  在前面我們定義的Handler的ProcessRequest方法中,我們調(diào)用了Executor.Execute,該方法用于執(zhí)行委托,實現(xiàn)如下:

        /// <summary>        /// 核心函數(shù),執(zhí)行Handler的方法        /// </summary>        /// <param name="page">頁面對象</param>        /// <param name="context">請求上下文</param>        /// <param name="cacheMethodInfo">緩存方法原數(shù)據(jù)</param>        internal static void Execute(Page page, HttpContext context, CacheMethodInfo methodInfo)        {            if (page == null)            {                throw new ArgumentNullException("page");            }            try            {                if (methodInfo != null)                {                    HttpRequest request = context.Request;                    object[] parameters = GetParametersFromRequest(request, methodInfo.Parameters);                    object data = methodInfo.Func(page, parameters);                    int serverCache = methodInfo.AjaxMethodAttribute.ServerCache;                    if (serverCache > 0)                    {                        CacheHelper.Insert(context, methodInfo.AjaxMethodAttribute.ServerCache, data);                    }                    EndCurrentRequest(context, data, methodInfo.AjaxMethodAttribute.OutputCache);                }                else                {                    EndCurrentRequest(context, "找不到合適的Ajax方法!");                }            }            catch (FormatException)            {                EndCurrentRequest(context, "調(diào)用方法匹配到無效的參數(shù)!");            }            catch (InvalidCastException)            {                EndCurrentRequest(context, "參數(shù)轉(zhuǎn)換出錯!");            }            catch (System.Threading.ThreadAbortException)            {                //do nothing            }            catch (Exception ex)            {                EndCurrentRequest(context, ex.Message);            }        }
View Code

  CacheMethodInfo我們已經(jīng)獲得了,現(xiàn)在只要獲得參數(shù)我們就可以執(zhí)行方法。

  GetParameterFromRequest用于從請求獲取object[]參數(shù)數(shù)組。根據(jù)上面所說的,如果參數(shù)是一個簡單類型,那么直接進行轉(zhuǎn)換;如果是實例對象,那么我們先要創(chuàng)建new一個實例對象,然后為其字段或?qū)傩再x值。實現(xiàn)如下:

        /// <summary>        /// 從請求獲取參參數(shù)        /// </summary>        /// <param name="request">HttpRequest</param>        ///<param name="parameters">參數(shù)信息</param>        /// <returns>參數(shù)數(shù)組</returns>        private static object[] GetParametersFromRequest(HttpRequest request, ParameterInfo[] parameters)        {            if (parameters.IsNullOrEmpty())            {                return null;            }            int length = parameters.Length;            object[] realParameters = new object[length];            for (int i = 0; i < length; i++)            {                ParameterInfo pi = parameters[i];                Type piType = pi.ParameterType.GetRealType();                object value = null;                if (piType.IsValueType())                {                    //值類型                    value = ModelUtil.GetValue(request, pi.Name, piType);                    value = value ?? Activator.CreateInstance(piType);                }                else if (piType.IsClass)                {                    //引用類型                    object model = ModelUtil.CreateModel(piType);                    ModelUtil.FillModelByRequest(request, pi.Name, piType, model);                    value = model;                }                else                {                    throw new NotSupportedException(pi.Name + " 參數(shù)不被支持");                }                realParameters[i] = value;            }            return realParameters;        }
View Code

  ModelUtil會從Http Request獲取參數(shù),并進行類型轉(zhuǎn)換處理:

    internal static class ModelUtil    {        /// <summary>        /// 緩存構(gòu)造函數(shù)        /// </summary>        private static Hashtable constructorTable = Hashtable.Synchronized(new Hashtable());         /// <summary>        /// 根據(jù)名稱從HttpRequest獲取值        /// </summary>        /// <param name="request">HttpRequest</param>        /// <param name="name">鍵名稱</param>        /// <param name="type">參數(shù)類型</param>        /// <returns></returns>        public static object GetValue(HttpRequest request, string name, Type type)        {            string[] values = null;            if (string.Compare(request.RequestType, "POST", true) == 0)            {                values = request.Form.GetValues(name);            }            else            {                values = request.QueryString.GetValues(name);            }            if (values.IsNullOrEmpty())            {                return null;            }            string data = values.Length == 1 ? values[0] : string.Join(",", values);            return Convert.ChangeType(data, type);        }        /// <summary>        /// 創(chuàng)建實例對象        /// </summary>        /// <param name="type">實例類型</param>        /// <returns></returns>        public static object CreateModel(Type type)        {            if (type == null)            {                throw new ArgumentNullException("type");            }            Func<object> func = constructorTable[type.AssemblyQualifiedName] as Func<object>;            if (func == null)            {                   func = ReflectionUtil.GetConstructorDelegate(type);                constructorTable[type.AssemblyQualifiedName] = func;            }            if (func != null)            {                return func();            }            return null;        }        /// <summary>        /// 填充模型        /// </summary>        /// <param name="request">HttpRequest</param>        /// <param name="name">鍵名稱</param>        /// <param name="prefix">參數(shù)類型</param>        /// <parparam name="model">實例對象</parparam>        public static void FillModelByRequest(HttpRequest request, string name, Type type, object model)        {            if (model == null)            {                return;            }            IEnumerable<DataMember> members = DataMemberManager.GetDataMember(type);            if (members.IsNullOrEmpty())            {                return;            }            object value = null;            foreach (DataMember member in members)            {                value = GetValue(request, string.Format("{0}.{1}", name, member.Name), member.MemberType);                value = value ?? GetValue(request, member.Name, member.MemberType);                member.SetValue(model, value);            }        }    }
View Code

  如果是引用類型,需要通過構(gòu)造函數(shù)創(chuàng)建對象,像前面用于,這里我們也用Expression來構(gòu)建一個Func<object>類型的委托來優(yōu)化,它調(diào)用了ReflectionUtil.GetConstructorDelegate方法。實現(xiàn)如下:

        /// <summary>        /// 獲取構(gòu)造函數(shù)委托        /// </summary>        /// <param name="type">實例類型</param>        /// <returns></returns>        public static Func<object> GetConstructorDelegate(Type type)        {            if (type == null)            {                throw new ArgumentNullException("type");            }            ConstructorInfo ci = type.GetConstructor(Type.EmptyTypes);            if (ci == null)            {                throw new MissingMemberException("類型必須有一個無參public構(gòu)造函數(shù)!");            }            NewExpression newExp = Expression.New(type);            Expression<Func<object>>  lambda = Expression.Lambda<Func<object>>(newExp);            return lambda.Compile();        }
View Code
  最后再輸出結(jié)果時,如果是Get請求,并且需要緩存,我們還需要設(shè)置一下Response.Cache。如下:
        private static void EndRequest(HttpContext context, object data, int outPutCache, ContentType contentType)        {            HttpResponse response = context.Response;            if (outPutCache != 0)            {                if (string.Compare(context.Request.HttpMethod, "GET", true) == 0)                {                    if (outPutCache > 0)                    {                        response.Cache.SetCacheability(HttpCacheability.Public);                        response.Cache.SetMaxAge(new TimeSpan(0, 0, outPutCache));                        response.Cache.SetExpires(DateTime.Now.AddSeconds(outPutCache));                    }                    else                    {                        response.Cache.SetCacheability(HttpCacheability.NoCache);                        response.Cache.SetNoStore();                    }                }            }            response.ContentType = GetContentType(contentType);            response.ContentEncoding = System.Text.Encoding.UTF8;            if (data != null)            {                response.Write(data);            }            response.End();        }
View Code
總結(jié)
  現(xiàn)在不管我們前臺用什么腳本庫,只要按照約定就可以調(diào)用標(biāo)記方法。上面已經(jīng)介紹了組件的核心部分,您也可以按照自己的想法進行擴展,也歡迎共同學(xué)習(xí)交流。
  源碼下載

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 城口县| 杭锦旗| 林西县| 安溪县| 岑巩县| 永城市| 灵寿县| 临桂县| 六枝特区| 巩义市| 广河县| 门源| 康定县| 思南县| 高阳县| 海淀区| 西和县| 福州市| 阿勒泰市| 娱乐| 景德镇市| 贡山| 深州市| 普安县| 潼关县| 庆城县| 通榆县| 鹤岗市| 集安市| 尚志市| 麻阳| 油尖旺区| 阳原县| 乐清市| 辽源市| 铜陵市| 宜兰县| 田阳县| 昭觉县| 津市市| 江陵县|