這里我要實現類似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頁面就可以直接體驗效果了。文章寫的比較匆忙,如果你有任何疑問或建議都請告訴我。。。好啦,就到這里吧
文件下載:下載