反射+特性打造簡潔的AJAX調用


這里我要實現類似AjaxPro組件調用效果的功能,先看看AjaxPro在CS文件中的代碼是怎么寫的。

//在后台寫的有參方法

[AjaxPro.AjaxMethod]

public string getString(string str)

{

return str + "Say: hello my friends";

}

前台頁面的調用方式

function Button4_onclick() {

var str=document.getElementByIdx_x("<%=TextBox1.ClientID %>").value;

WebUI._Default.getString(str,getStringCallBack);

}

這樣的調用代碼相當於在客戶端直接執行了服務器端代碼,然后取到執行結果,是不是有點意思,接下來我們就來自己把這類似的功能實現一把。

不過在實現之前你最好對反射和特性的基本運用有一定的了解,馬上進入正題。

 

首先我們來理一下實現的思路

1.定義能應用在方法上的Ajax標識特性,因為並不是Page對象的所有方法都需要公開被調用,可以用特性做一個標記,可以通過MethodAliasName屬性為方法設置一個方法別名,這樣做的目的主要是為了安全和AJAX調用代碼更簡潔。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace AjaxInvokeDemo.Ajax
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
    public class AjaxMethodAttribute : Attribute
    {
        /// <summary>
        /// 設置ajax調用時的方法別名
        /// </summary>
        public string MethodAliasName
        {
            get;
            set;
        }
    }
}

 

2.定義頁面基類,在里面實現一些公用的邏輯。比如獲取要執行的方法的名稱以及方法的參數,並通過反射對方法進行調用。具體還是看代碼吧,可能更清楚一點。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Runtime;
using System.Reflection;
using System.Collections.Specialized;
namespace ConfigDemo.Ajax
{
    public abstract class AjaxPage<T> : System.Web.UI.Page
    {
        private static readonly string AjaxMethodCacheName = "AjaxMethods";
        private string pageName = typeof(T).Name;
        private Type pageType = typeof(T);
       
        protected override void OnPreInit(EventArgs e)
        {
            if (Cache[AjaxMethodCacheName] == null)
            {
                AjaxMethods = AjaxHelper.GetAjaxMethods<T>();
                Cache[AjaxMethodCacheName] = AjaxMethods;
            }
            else
            {
                AjaxMethods = Cache[AjaxMethodCacheName] as Dictionary<string, string>;
            }
            base.OnPreInit(e);
        }

        protected override void OnLoad(EventArgs e)
        {
            ExecuteAction();
            base.OnLoad(e);
        }

        public Dictionary<string, string> AjaxMethods
        {
            get;
            set;
        }

        /// <summary>
        /// Action名稱或者別名
        /// </summary>
        public string CurrentActionName
        {
            get
            {
                if (!string.IsNullOrEmpty(HttpContext.Current.Request["action"]))
                {
                    return HttpContext.Current.Request["action"];
                }
                throw new Exception("調用時必須指定Action參數..");
            }
        }

        /// <summary>
        /// 傳遞的參數集合
        /// </summary>
        public object[] CurrentParams
        {
            //一般的調用URL格式為 http://xxxxx/yyy.aspx?action=method&id=a001 ...
            get
            {
                NameValueCollection NVs = HttpContext.Current.Request.QueryString;
                object[] objs = new object[NVs.Count-1]; //這里將action參數排除在外
                for(int i =1;i<NVs.Count; i++)
                {
                    objs[i-1] = NVs[i];
                }

                return objs;
            } 
        }

        /// <summary>
        /// 最終要執行的Page的方法的真實名稱
        /// </summary>
        public string CurrentAjaxMethodName
        {
            get;
            set;
        }

        public void ExecuteAction()
        {
            if (!AjaxMethods.ContainsKey(CurrentActionName) && !AjaxMethods.ContainsValue(CurrentActionName))
            {
                throw new Exception("調用的方法不存在或者未被公開為Ajax方法..");
            }

            //沒有為Ajax方法指定別名
            if (AjaxMethods.ContainsKey(CurrentActionName) && AjaxMethods[CurrentActionName] == CurrentActionName)
            {
                CurrentAjaxMethodName = CurrentActionName;
            }
            else
            {
                //為Ajax方法指定了別名
                CurrentAjaxMethodName = AjaxMethods.First<KeyValuePair<string, string>>(x => x.Value == CurrentActionName).Key;
            }

            MethodInfo method = pageType.GetMethod(CurrentAjaxMethodName);
            if (method != null)
            {
                object PageObj = GetPageInstance();
                method.Invoke(PageObj, CurrentParams);
            }
            
        }


        public object GetPageInstance()
        {

            if (Cache[pageName] == null)
            {
                object PageObj = Activator.CreateInstance(pageType);
                return Cache[pageName] = PageObj;
            }
            else
            {
                return Cache[pageName] as object;
            }
        }


        
    }
}

 

3.為了獲取被標識為AjaxMethod的方法集合,這里專門用一個AjaxHelper類實現。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Reflection;
namespace ConfigDemo.Ajax
{
    public class AjaxHelper
    {
        /// <summary>
        /// 獲取指定Page對象中標記為Ajax的方法集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="page"></param>
        /// <returns></returns>
        public static Dictionary<string,string> GetAjaxMethods<T>()
        {
            Dictionary<string, string> ajaxMethods = new Dictionary<string, string>();
            AjaxMethodAttribute ajaxMethodAttribute = null;
            //方法別名
            string methodAliasName = string.Empty;
           
            Type t = typeof(T);
            MethodInfo[] methods = t.GetMethods();
            foreach (MethodInfo method in methods)
            {
                object[] attributes = method.GetCustomAttributes(typeof(AjaxMethodAttribute), false);
                if (attributes != null && attributes.Length > 0)
                {
                    ajaxMethodAttribute = (AjaxMethodAttribute)attributes[0];
                    //如果沒有為ajax調用方法設置別名則用方法本身的名稱
                    methodAliasName = string.IsNullOrEmpty(ajaxMethodAttribute.MethodAliasName) == true ? method.Name : ajaxMethodAttribute.MethodAliasName;
                    ajaxMethods.Add(method.Name, methodAliasName);
                }
            }

            return ajaxMethods;
        }
    }
}

 

4.基礎框架搭建完畢,看看怎么使用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using System.Reflection;
using System.Text;

namespace AjaxInvokeDemo.Ajax
{
    public partial class Index : AjaxPage<Index>
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            
        }

        [AjaxMethod]
        public void GetPerson(string id)
        {
           List<Person> ps = new List<Person>();
           ps.Add(new Person
           {
               Id = "a001",
               Name = "abc",
               Sex = "",
               Age = 20
           });

           ps.Add(new Person
           {
               Id = "a002",
               Name = "xyz",
               Sex = "",
               Age = 18
           });

           ps.Add(new Person
           {
               Id = "a003",
               Name = "zzzz",
               Sex = "",
               Age = 28
           });

           ps.Add(new Person
           {
               Id = "a004",
               Name = "yyy",
               Sex = "",
               Age = 21
           });

           StringBuilder builder = new StringBuilder();
           Person person = ps.Find(p => p.Id == id);
           if (person != null)
           {
               //http://htmltextwriterutil.codeplex.com/ 這是htmltextwriter工具的下載地址,一款拼字符串的好工具
               builder.Append("   <ul>");
               builder.AppendFormat("      <li>編號:{0}</li>",person.Id);
               builder.AppendFormat("      <li>姓名:{0}</li>", person.Name);
               builder.AppendFormat("      <li>性別:{0}</li>", person.Sex);
               builder.AppendFormat("      <li>年齡:{0}</li>", person.Age);
               builder.Append("   </ul>");
           }

           HttpContext.Current.Response.Write(builder.ToString());
           HttpContext.Current.Response.End();
        }
    }

    
    public class Person
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public string Sex { get; set; }
        public int Age { get; set; }
    }
}

這里的使用有兩個要點,一是頁面要繼承自AjaxPage<T>泛型類,第二是在要被客戶端調用的方法上加上[AjaxMethod]特性,一切就這么簡單。。

 

5.客戶端調用

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AjaxTest.aspx.cs" Inherits="AjaxInvokeDemo.Ajax.AjaxTest" %>

<!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>
    <script type="text/javascript" src="../Scripts/jquery-1.4.1.min.js"></script>
    <script type="text/javascript">
      $(function(){
      $("#btn").click(function(){
          $("#box").load("Index.aspx?action=GetPerson&id="+$("#txtId").val());
      });
    });
    </script>
    
</head>
<body>
    <form id="form1" runat="server">
    用戶ID:<input type="text" id="txtId" value="a001"/><input type="button" id="btn" value="查詢"/>
    <div id="box">
    </div>
    </form>
</body>
</html>

 至此,調用完畢。。。

 

最后,還是附上代碼吧。下載網站項目之后里面你會看到一個叫做AJAx的文件夾,里面就是所有代碼了,運行AjaxTest.aspx頁面就可以直接體驗效果了。文章寫的比較匆忙,如果你有任何疑問或建議都請告訴我。。。好啦,就到這里吧

文件下載:下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM