一.前言
在之前的一篇隨筆中已經講述過控制器,而今天的隨筆是作為之前的擴展。
二.正文
1.自定義動作方法
相信大家在開發過程一定會遇到動作方法的重名問題,雖然方法的名稱和參數一樣,但是里面的邏輯是不一樣的,因為你設置了對應的注解屬性可以確定調用哪個動作方法。這個時候你就需要將動作的名稱與方法的名稱區別開來,那么你就可以使用ActionName注解屬性。比如我們要求一個頁面在本地訪問與非本地訪問時呈現不同的頁面,但是你又想用不同的方法區分開來寫,那么這個時候你就可以使用這個注解屬性了,比如下面的代碼:
1 [ActionName("Index")] 2 public ActionResult LocalIndex() 3 { 4 return View(); 5 } 6 7 public ActionResult Index() 8 { 9 return View(); 10 }
雖然第一個方法的名稱叫做LocalIndex,但是最終頁面的名稱還是按照ActionName中設置的名稱去查詢,所以讀者千萬不要還是按照方法的名稱去新建視圖,這樣是錯的。
2.非動作方法
從開始學到現在,大家都一定發現只要寫在控制器中的公開方法最后都是一個動作方法(簡單說就是對應一個頁面),但是我們有時需要一個公開的方法,但是它又不是一個動作方法,僅僅只是為了便於單元測試,那么我們該怎么辦?ASP.NET MVC一樣還是想到了這些,為我們提供了NonAction注解屬性,因為使用很簡單所以就不單獨舉例了。
3.自定義動作方法選擇器
上面的第一節介紹了動作方法可以是同一個名字,並且參數也可以完全一樣,那么控制器如何去判斷執行哪個動作方法呢?其中一個就是根據動作方法選擇器(就是動作方法的注解屬性)的返回值去過濾匹配的動作方法,ASP.NET MVC現成的有HttpPost等,當然我們也可以自定義,只要實現下面這個抽象類中的IsValidForRequest方法即可:
1 [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] 2 public abstract class ActionMethodSelectorAttribute : Attribute 3 { 4 protected ActionMethodSelectorAttribute(); 5 6 public abstract bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo); 7 } 8 9 其中MethodInfo 中包含的關於動作方法的信息。 10 11 下面是筆者的一個示例,可以根據form表單的值決定是否執行該動作方法: 12 public class LoginAttribute : ActionMethodSelectorAttribute 13 { 14 bool _isFirst; 15 16 public LoginAttribute(bool isFirst) 17 { 18 _isFirst = isFirst; 19 } 20 21 public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo) 22 { 23 24 string obj = controllerContext.HttpContext.Request.Form["loginType"]; 25 if (obj != null) 26 { 27 if (_isFirst) 28 { 29 if (obj.Equals("true")) 30 return true; 31 } 32 else 33 { 34 if (obj.Equals("false")) 35 return true; 36 } 37 } 38 return false; 39 } 40 }
4.異步控制器
相信從事ASP.NET的人一定會知道異步這個概念,這個概念不僅僅只是在ASP.NET中即使在ASP.NET MVC中也一樣存在,只是稍有變化,如果這個控制器中含有異步的方法,那么我們就需要繼承AsyncController類,並且需要異步的動作方法要分成兩個部分,第一個執行異步操作的方法,命名需要為 動作方法名+Async,當異步操作執行完成之后將調用 動作方法名+Completed方法,特別注意方法的規范,如果名稱不對可能就無法看到異步控制器的正確執行結果,筆者有一個簡單的示例:
1 namespace MvcStudy.Controllers 2 3 { 4 5 [SessionState(System.Web.SessionState.SessionStateBehavior.Disabled)] 6 7 public class TestController : AsyncController 8 9 { 10 11 [NoAsyncTimeout] 12 13 public void IndexAsync() 14 15 { 16 17 AsyncManager.OutstandingOperations.Increment(); 18 19 Task.Factory.StartNew(() => 20 21 { 22 23 Thread.Sleep(2000); 24 25 AsyncManager.Parameters["data"] = "test"; 26 27 AsyncManager.OutstandingOperations.Decrement(); 28 29 }); 30 31 } 32 33 34 35 public ActionResult IndexCompleted(string data) 36 37 { 38 39 ViewBag.Data = data; 40 41 return View(); 42 43 } 44 45 } 46 47 }
這里我們使用Increment方法開啟一個異步操作(該方法可以傳遞數字表示要開啟幾個異步操作),然后就是利用StartNew開始我們的一個異步操作,在異步操作完成之后將數據放入Parameters中,這樣我們就可以通過IndexCompleted的參數中獲得,異步操作最后調用Decrement方法標識一個異步操作完成。IndexAsync動作方法上還存在一個注解屬性(NoAsyncTimeout),標識該異步操作沒有超時限制,如果你需要設置一個超時可以用AsyncTimeout,並傳入一個以毫秒為單位的時間,如果異步操作的執行超時則會產生TimeOutException類型的異常。
讀者一定會疑惑SessionState這個注解屬性是干什么的,大家一定會熟悉ASP.NET中的一般處理程序,默認都是不可以訪問Session其目的就是提高性能,那么在ASP.NET MVC中我們就可以通過SessionState使該控制器不需要維護Session,當然我們也就無法在這個控制器中訪問Session了,但是卻可以得到性能的提升。