在跟html+ashx打交道的園友們肯定會發現,這種模式雖然優美,但在開發中會遇到一些難處理的地方。我也不例外,下面是自己在實際開發中總結出來的幾條經驗,希望跟大家分享,更希望得到大家的建議和更好的解決方法!
問題1:用委托字典代替switch...case。
這個問題是在處理請求時發現的,大家肯定也不願意在自己的項目中建許多的handler來處理那麼多的請求,於是就想到在一個handler裡處理多個請求,ajax請求中都加一個action的參數,在handler裡根據這個action做相應的處理或返回相應的數據,這裡肯定沒有人用if...else來判斷action,大多數人都會想到用switch...case,一開始我也是用的switch,但漸漸地發現,每個case不像一個代碼塊,不能為其中的變量提供一個獨立的作用域!用龍珠中孫悟空的話“真是傷腦筋”。
在網上搜了一下,也有不少人遇到這個問題。有個解決方法是把每個處理單獨成handler裡一個方法,這樣清楚明了,但在ProcessRequest方法中要用反射調用對應的方法!自己對這個解決辦法不太滿意,於是想到了委托,想到了字典,把反射調用方法變成在字典裡索引委托。
首先在handler裡聲明一個私有的靜態委托字典:
static Dictionary<string, Func<string>> hs;
然後用handler(一般處理程序的類)裡靜態構造函數初始化hs,更重要的是要在靜態構造函數裡添加處理方法:
static Handler() { hs = new Dictionary<string, Func<string>>(); hs.Add("add", delegate() { int id = int.Parse(req("id")); string title = req("title"); return "add"; }); hs.Add("update", delegate() { int id = int.Parse(req("id")); string title = req("title"); return "update"; }); }
最後就是在ProcessRequest方法裡調用了:
context.Response.ContentType = "text/plain"; HttpRequest req = context.Request; string action = req["action"].ToLower(); string result = hs[action](); context.Response.Write(result);
這樣便避免了switch...case的變量作用域問題和反射的效率問題。關於上面用到的req()方法,我的想法是把公共的東西用靜態方法提供,如:
static string req(string key) { return HttpContext.Current.Request[key]; } static string jss(object obj) { JavaScriptSerializer JSS = new JavaScriptSerializer(); return JSS.Serialize(obj); }
問題2:權限問題。
你肯定不願自己的數據在用戶沒有登陸或登陸過期後還可以繼續訪問。這裡假設登陸的用戶用Session["user"]來存儲,當然在handler裡判斷一下Session["user"]是很簡單的事情,但問題是你如何讓Session["user"]為null時的用戶跳轉到指定頁(這裡假設是登陸頁login.html)。哈哈,這時你會不會想到用context.Response.Redirect ("login.html")這樣一句話來解決呢!我的第一反映是這樣的,但分析一下,ajax是請求數據的,這樣做是讓ajax去請求login.html這個頁面,得到的結果應該是login.html的源代碼才對,分析是這樣分析的,可還是不死心,還是測試了一下,結果正如分析的那樣,login.html的源代碼做為ajax請求結果返回了!
其實,大家心理明白,有一個很簡單的方法,就是在Session["user"]為null時返回一個特定值,這裡假設"unlogin",然後在每次ajax請求完成後判斷返回值是不是"unlogin"。
這方法很簡單,也很可靠,但很笨,很麻煩,可行性不高。於是我又想到了jquery.ajaxSuccess(),想用它來做統一處理,在我想到它的時候我就有點兒擔心,jquery會不會是先調用具體請求的回調函數然後再調用這全局的回調函數呢?我帶著這個疑問做了測試,結果也如預料那樣先執行具體請求的回調再執行全局回調!沒法辦,只好查jquery的源碼了~。在沒壓縮的jquery-1.4.2.js裡找到了success()這方法,果然如此,改順序後如下:
function success() { if ( s.global ) { trigger( "ajaxSuccess", [xhr, s] ); } // If a local callback was specified, fire it and pass it the data if ( s.success && xhr.responseText!="unlogin" ) { s.success.call( callbackContext, data, status, xhr ); } }