近期用asp.net做個小網站,但又不喜歡使用asp.net的服務器端控件,經過一番思量后確定前端采用原始的html、后台采用Linq to Sql與數據庫交互,Linq上面創建一業務邏輯層,而web前端通過使用jQuery的ajax方法異步調用asp.net的一般處理程序(handler),實現與后台的業務邏輯層交互,至此大方向開發框架確立,只是細節上jQuery調用ashx有點小麻煩,一次只能調用一個ashx類,如此這般,一個模塊增、刪、改、查一套功能下來我不是得創建多個handler類?項目雖小,但這樣做下來勢必會產生很多ashx文件,對代碼管理與閱讀相當的不便,如果一個完整的功能模塊下來只對應一個handler類該多好,通過調用同一個handler類執行不同方法來完成一模塊中的不同的功能,就像java的strus框架的Action那樣,經過思考隱約覺得使用反射機制可以實現上述想法,然后又百度了一下參考前人經驗,經過實驗確實可行,做了如下總結:
(1).使用反射機制的Invoke方法需要引用System.Reflection類。在使用jQuery的Ajax方法時,固定一個傳值參數用來向handler類傳送要執行的指定方法,參數可以隨便命,但確定下來后就不能更改,我這里統一命名為"Action"。
(2).為節省勞動力與成本,避免重復編碼我創建名為"BaseHandler.ashx"的基類,在這個類里邊除了實現反射外,同時提供了一些通用方法以方便繼承它的子類調用,所有的Handler類均繼承該類。主要代碼如下:

1 /// <summary> 2 /// 通過反射機制執行指定方法 3 /// </summary> 4 /// <param name="context"></param> 5 public void ProcessRequest(HttpContext context) 6 { 7 const string MESSAGE = "無法獲取參數值或參數值不正確。"; 8 9 string strAction = ""; 10 Object[] objParameter; 11 Type[] objParamType; 12 Type objMethodType; 13 MethodInfo objMethod; 14 15 //獲取參數傳遞(Acion為要執行的方法名) 16 strAction = GetRequest(context, "Action"); 17 if (strAction != "") 18 { 19 //獲取調用類的類型 20 objMethodType = this.GetType(); 21 22 //設置方法參數值,並存入數組(在這里將HttpContext作為方法的參數) 23 objParameter = new object[1]; 24 objParameter[0] = context; 25 26 //獲取參數的數據類型 27 objParamType = new Type[1]; 28 objParamType[0] = objParameter[0].GetType(); 29 30 //獲取指定的方法對象 31 objMethod = objMethodType.GetMethod(strAction, objParamType); 32 33 //如果存在,則進行調用並返回給前台頁面 34 if (objMethod != null) 35 { 36 context.Response.Write((string)objMethod.Invoke(this, objParameter)); 37 } 38 } 39 else 40 { 41 //異常提示信息 42 context.Response.Write(MESSAGE); 43 } 44 } 45 46 /// <summary> 47 /// 48 /// </summary> 49 public bool IsReusable 50 { 51 get 52 { 53 return false; 54 } 55 } 56 57 /// <summary> 58 /// 獲取指定鍵值的參數值 59 /// </summary> 60 /// <param name="context">HttpContext</param> 61 /// <param name="key">指定鍵</param> 62 /// <returns>String</returns> 63 public String GetRequest(HttpContext context, String key) 64 { 65 String strRet = ""; 66 67 //如果指定鍵值的參數存在,則獲取 68 if (context.Request[key] != null) 69 { 70 strRet = context.Request[key].ToString(); 71 } 72 73 return strRet; 74 }
這里有幾個注意點:在實現ProcessRequest方法中,頁面參數傳值的獲取上我這里只獲取了Action參數的值:strAction = GetRequest(context, "Action");也就是要執行的方法名,而在實際應用中傳值參數不止一個,不同的調用方法有不同的參數,當然在這里也可以全部獲取存入數組中最后交給Invoke,但個人覺得沒有必要在這在獲取所有的傳值,僅Action足已,因為Action是固定的,其他的參數可以交由要處理的Action方法去接收,怎么接收?我把HttpContext作為要執行的方法的參數傳進去了:objParameter[0] = context;在執行定指的方法里邊可以通過context對象再次獲取頁面傳值,這樣做的好處是代碼清晰,分工明確,業務邏輯清晰簡單。
(3).再看BaseHandler的子類,假設我們現在對用戶管理這一模塊來實現,該模塊有用戶登錄、添加、刪除、修改、列表等功能,將這些功能的實現方法統一放在UserHandler.ashx類中,在該類中只做了簡單用戶登錄演示,其他功能都可觸類旁通,代碼如下:

1 /// <summary> 2 /// UserHandler 的摘要說明 3 /// </summary> 4 public class UserHandler : BaseHandler 5 { 6 /// <summary> 7 /// 用戶登錄處理 8 /// </summary> 9 /// <param name="context"></param> 10 /// <returns></returns> 11 public String Login(HttpContext context) 12 { 13 String strAccount = ""; 14 String strPassword = ""; 15 String strRet; 16 17 try 18 { 19 20 //獲取頁面傳值 21 strAccount = GetRequest(context, "Account"); 22 strPassword = GetRequest(context, "Password"); 23 24 if (strAccount != "" && strPassword != "") 25 { 26 //簡單起見,僅返回傳遞過來的用戶賬號與密碼 27 //在實際應用中利用傳遞過來的參數值調用業務邏輯層的方法來完成客戶端的請求 28 strRet = String.Format("賬號:{0},密碼:{1}", strAccount, strPassword); 29 } 30 else 31 { 32 //返回提示信息 33 strRet = "未能正確獲取參數!"; 34 } 35 36 return strRet; 37 } 38 catch (Exception ex) 39 { 40 throw ex; 41 } 42 } 43 44 }
在這里我們只有一個Login方法參數為HttpContext類,而在這個方法里邊我們可以通過HttpContext類再次獲取除了Action以外的頁面傳值,代碼應該是相當清晰的,注意在這里不需要再實現ProcessRequest與IsReusable方法,可以直接刪去。
(4).Html網站前端調用UserHandler.ashx代碼:

1 <script type="text/javascript"> 2 $(document).ready(function () { 3 $("#btnLogin").click(function () { 4 var account; 5 var password; 6 7 account = $("#txtUserName").val(); 8 password = $("#txtPassword").val(); 9 10 $.ajax({ 11 type: "POST", 12 async: true, 13 url: "Handler/UserHandler.ashx", 14 dataType: "text", 15 data: { Action: "Login", Account: account, Password: password }, 16 success: function (data) { 17 alert(data); 18 }, 19 error: function (xhr) { 20 alert(xhr.statusText); 21 return false; 22 } 23 }); 24 }); 25 }); 26 </script>
調用URL:UserHandler.ashx,傳值參數:data: { Action: "Login", Account: account, Password: password },除了Login方法外還有賬號與密碼,堅持一切從簡原則,回調函數只是alert了一下返回結果,從UserHandler.ashx的Login方法中不難看出,如果調用成功alert的應該是:"賬號:你輸入的賬號,密碼:你輸入的密碼"。到此一條路線已打通,其他的功能實現照樣畫葫蘆就行。
(5).關於方法重載,我在百度的時候也看到過類似的介紹,也給了我很多的啟示,但很多人都問到方法重載的問題如何解決,就沒有下文了,其實實現重載也很簡單,在同一方法里邊根據你獲取參數的多少與不同,間接的去調用重載方法不就解決問題了嗎?