在當前WEB當中,有些人都會拋棄asp.net的服務器控件,轉而使用ajax來進行數據的交互和存儲.
當我們大量使用ajax的時候,對於新手而言,肯定會創建很多的ashx或aspx頁面,通過拼接參數,在ashx或aspx中對參數進行解析,
並根據某些特定的參數進行解析來判斷當前的請求屬於哪種類型的操作,然后手動獲取Request.QueryString、Params、Form內的值,來實現功能.大致代碼如下:
View Code
1 //html 2 名字:<input id="name" type="text"/> 3 <input type="button" value="查詢" onclick="search()"/> 4 <script type="text/javascript"> 5 function search(){ 6 var name = $('#name').val(); 7 //省略驗證過程 8 $.ajax({ 9 url: 'Customer.ashx', 10 data: { type: 'search', name : name }, 11 dataType: 'json', 12 success: function(json){ 13 //對於獲取的數據執行相關的操作,如:綁定、顯示等 14 } 15 }); 16 }; 17 </script> 18 //ashx 19 public void ProcessRequest(HttpContext context) 20 { 21 var type = context.Request.Params["type"]; 22 if(type == "search") 23 { 24 var name = context.Request.Params["name"]; 25 //獲取數據,並轉化為json 26 var json = ...//省略 27 context.Response.Write(json); 28 } 29 }
在大量的重復這些編寫這些代碼的情況下,眾多的新手們肯定都會跟我一樣,蛋疼啊,而且隨着業務及模塊的不斷增加,這些個ashx或aspx,那個量還不是一般的多呢.
而且每個都只是做一些判斷,根本沒什么重要的業務在里面,於是乎我們就在想,有沒有什么方法可以讓我們在ajax內傳遞某些參數,達到直接反射類,訪問對應的方法,自動處理參數等.
根據以上的一些要求,的確可以讓我們在編碼過程當中,減少很多的困惑和麻煩.那我們現在就一步步開始吧.
首先,我們先從ajax開始,傳遞某些特定的值來反射對應的類,那么我們的第一反應就是將類的整個完整命名傳遞過去(因為我們並不能保證所有要調用的類都在同一個程序集內).
那么我們就在js內定義2個參數分別為assembly和fullName吧.我們假設Customer業務類的FullName為SysBLL.CustomerBLL且所在的程序集為SysBLL.
那么前面的例子ajax的修改大致如下:
View Code
1 <script type="text/javascript"> 2 function search(){ 3 var name = $('#name').val(); 4 //省略驗證過程 5 $.ajax({ 6 url: 'BLLAshx.ashx', 7 data: { assemlby : 'SysBLL', fullName: 'SysBLL.CustomerBLL', method: 'Search', name : name }, 8 dataType: 'json', 9 success: function(json){ 10 //對於獲取的數據執行相關的操作,如:綁定、顯示等 11 } 12 }); 13 }; 14 </script>
從我們的需求上,我們了解到,我們只需要一個ashx來作為代理,去反射對應的類和方法,並從傳遞的參數中過濾出方法所需要的參數,最后調用方法取得返回值.代碼大致如下:
View Code
1 View Code 2 //ashx 3 namespace Common 4 { 5 public class BLLAshx : IHttpHandler 6 { 7 public void ProcessRequest(HttpContext context) 8 { 9 string assemblyName = context.Request.QueryString["assemlby"], fullName = context.Request.Params["fullName"]; 10 var bllType = Assembly.Load(assemblyName).GetType(fullName); 11 12 var methodName = context.Request.Params["method"]; 13 var method = bllType.GetMethod(methodName); 14 if (null != method) 15 { 16 string[] parameterValues = GetMethodParameterValues(context.Request, method); 17 18 var instance = Activator.CreateInstance(bllType); 19 20 var result = method.ReturnType == typeof(void) ? "{}" : method.Invoke(instance, parameterValues).ToString(); 21 22 //以上Invoke省略了判斷以及捕捉異常 23 context.Response.Write(result); 24 } 25 else 26 { 27 //返回不存在方法的提示 28 } 29 } 30 31 private string[] GetMethodParameterValues(HttpRequest request, MethodInfo method) 32 { 33 string[] parameterValues = null; 34 var methodParameters = method.GetParameters(); 35 if (0 < methodParameters.Length) 36 { 37 parameterValues = new string[methodParameters.Length]; 38 for (int i = 0; i < methodParameters.Length; i++) 39 { 40 parameterValues[i] = request.Params[methodParameters[i].Name]; 41 } 42 } 43 return parameterValues; 44 } 45 } 46 } 47 //CustomerBLL 48 namespace SysBLL 49 { 50 public class CustomerBLL 51 { 52 public string Search(string name) 53 { 54 var json = ...//獲取數據 55 return json; 56 } 57 } 58 }
對於以上的ashx,我們需要在web項目中,新建一個名為BLLAshx的ashx文件,但是我們不要.cs的文件,並作如下修改:
<%@ WebHandler Language="C#" CodeBehind="BLLAshx.cs" Class="Common.BLLAshx" %>
現在我們再次回到ajax調用的地方,大家都會發現我們的參數列表室在太長了,因此大家可能會想用一些方法來改善,比如:連ashx都懶的重復去寫了,想直接在url中把彌命名空間、類、方法直接放進去來替代,想到這一步的時候,我們就需要配置web.config了,假設我們想要的規則是SysBLL/SysBLL.CustomerBLL.Search,配置如下:
<httpHandlers>
<add path="*/*.*.*.do" type="Common.BLLAshx" verb="GET,POST"/>
</httpHandlers>
有人會問為什么這邊要.do,而不直接省略呢?因為如果不加.do,那么就會將其他的請求也都轉向我們的ashx,例如:js、css文件等,大家可以自己測試看看.因為我們使用了地址映射,因此我們的js以及ashx代碼又要做一些改動了.大致修改如下:
View Code
1 View Code 2 //ashx 3 namespace Common 4 { 5 public class BLLAshx : IHttpHandler 6 { 7 public void ProcessRequest(HttpContext context) 8 { 9 string assemblyName = context.Request.QueryString["assemlby"], fullName = context.Request.Params["fullName"]; 10 var bllType = Assembly.Load(assemblyName).GetType(fullName); 11 12 var methodName = context.Request.Params["method"]; 13 var method = bllType.GetMethod(methodName); 14 if (null != method) 15 { 16 string[] parameterValues = GetMethodParameterValues(context.Request, method); 17 18 var instance = Activator.CreateInstance(bllType); 19 20 var result = method.ReturnType == typeof(void) ? "{}" : method.Invoke(instance, parameterValues).ToString(); 21 22 //以上Invoke省略了判斷以及捕捉異常 23 context.Response.Write(result); 24 } 25 else 26 { 27 //返回不存在方法的提示 28 } 29 } 30 31 private string[] GetMethodParameterValues(HttpRequest request, MethodInfo method) 32 { 33 string[] parameterValues = null; 34 var methodParameters = method.GetParameters(); 35 if (0 < methodParameters.Length) 36 { 37 parameterValues = new string[methodParameters.Length]; 38 for (int i = 0; i < methodParameters.Length; i++) 39 { 40 parameterValues[i] = request.Params[methodParameters[i].Name]; 41 } 42 } 43 return parameterValues; 44 } 45 } 46 } 47 //CustomerBLL 48 namespace SysBLL 49 { 50 public class CustomerBLL 51 { 52 public string Search(string name) 53 { 54 var json = ...//獲取數據 55 return json; 56 } 57 } 58 }
ashx的調整,我們只要修改ProcessRequest方法,代碼大致如下:
View Code
1 var reg = new Regex(@"(?<assembly>\w+)\/(?<class>\w+\.\w+)\.(?<method>\w+)\."); 2 var groups = reg.Match(context.Request.AppRelativeCurrentExecutionFilePath).Groups; 3 if (4 == groups.Count) 4 { 5 string assemblyName = groups["assembly"].Value, fullName = groups["class"].Value; 6 var bllType = Assembly.Load(assemblyName).GetType(fullName); 7 8 var methodName = groups["method"].Value; 9 var method = bllType.GetMethod(methodName); 10 if (null != method) 11 { 12 string[] parameterValues = GetMethodParameterValues(context.Request, method); 13 14 var instance = Activator.CreateInstance(bllType); 15 16 var result = method.ReturnType == typeof(void) ? "{}" : method.Invoke(instance, parameterValues).ToString(); 17 //以上Invoke省略了判斷以及捕捉異常 18 context.Response.Write(result); 19 } 20 else 21 { 22 //返回不存在方法的提示 23 } 24 } 25 else 26 { 27 //url匹配不正確 28 }
有人可能會問為什么要重復SysBLL/SysBLL呢?其實可以省略其中的一個,但是條件是程序集必須要跟這個前綴一樣才能省略.
如果大家想要省略其中一次SysBLL,那么正則的匹配規則也要相應的調整一下,只要將(?<class>\w+.\w+)中的.\w+去掉即可.
大致的實現流程就到這里了,我們已經將大部分的需求基本完成了,還有一些遺留的問題留給大家去完善啦,比如:調用的方法參數必須都是string類型,方法的返回值也必須要是string類型,反射的類不能是泛型類型的等等.
因為以上的代碼是隨着文章編寫的,因此沒有示例代碼,沒有辦法提供給大家,請見諒,呵呵.以上如有錯誤,請大家告訴我,多謝.
因為例子要簡單易理解,所以編碼方面不管是程序集、類名、方法名都是明碼,可能讓部分人有所錯覺,在實際開發當中,可以使用類似交易碼之類的來替代對應的程序集、類名、方法名,這樣就不會那么透明了,至於js方面的安全性,大家可以看看google的Gmail,以上僅僅是個人的理解,有錯誤,也希望大家能提出,呵呵。
