前幾天在博問中看到一個問題——Response.End()后,是否停止執行?MVC與WebForm不一致。看到LZ的描述后,雖然奇怪于為何用Response.End()而不用return方式去控制流程,但基于自己以往的認識,還是回答了說需要return。
因為以往的開發過程中,雖然沒有用過Response.End()的方式像LZ所說地那樣“方便地從多層調用中退出”,但是始終是認為Response.End()是不能終止其后代碼執行的,思維路線大概是:Response.End()只是結束了HTTP返回流的寫入,但是代碼依然沒有return啊,例如Page_Load中使用了Response.End(),但是這個方法并沒有被跳出/終止。
之后LZ編輯了問題,繼續提到了問題沒有解決,又附帶了偽代碼希望大家幫忙改進書寫方式。直到此時,由于自己的思維慣性,我依然我沒有去寫DEMO去驗證對比webform和mvc下的Response.End(),簡單地用主動throw new Exception的方式寫出了MVC下“好看一點”的代碼。
之后在回復中,LZ再次重復了Response.End()確實在webform和mvc中存在差異,我抱著試一試地心態測了一個療程。真的有點吃驚,Reponse.End()在webfrom和ASP.NET MVC下的表現確實是不同的!
webapi和mvc的區別。ASP.NET MVC代碼:
public ActionResult Index() {Method0();Method1();Method2();Response.Write("All methods success.");return View("I don't think so."); }private void Method0() {Debug.WriteLine("Method 0 process...");bool flag = true;if (!flag){Response.Write("Method 0 failure.");Response.End();} }private void Method1() {Debug.WriteLine("Method 1 process...");bool flag = false;if (!flag){Response.Write("Method 1 failure.");Response.End();} }private void Method2() {Debug.WriteLine("Method 2 process...");bool flag = false;if (!flag){Response.Write("Method 2 failure.");Response.End();} }
web頁面顯示:
調試信息輸出:
webform和winform的區別?Response.End()后的代碼繼續執行,這與之前的認識是沒有出入的,接下來看webform。
Webform代碼:
protected void Page_Load(object sender, EventArgs e) {Method0();Method1();Method2();Response.Write("All methods success."); }private void Method0() {Debug.WriteLine("Method 0 process...");bool flag = true;if (!flag){HttpContext.Current.Response.Write("Method 0 failure.");System.Web.HttpContext.Current.Response.End();} }private void Method1() {Debug.WriteLine("Method 1 process...");bool flag = false;if (!flag){HttpContext.Current.Response.Write("Method 1 failure.");System.Web.HttpContext.Current.Response.End();} }private void Method2() {Debug.WriteLine("Method 2 process...");bool flag = true;if (!flag){HttpContext.Current.Response.Write("Method 2 failure.");System.Web.HttpContext.Current.Response.End();} }
web頁面輸出:
調試信息:
Spring MVC的工作原理是怎樣的?
web頁面的輸出一致,調試窗口那里可是大不一樣。webform并未接著執行Response.End()后的代碼,因為拋出了一個ThreadAbortException異常。這時候,我首先想到的是ASP.NET MVC下的Response對象類型是否和ASP.NET不同,導致他們的處理方式不同。
后來發現雖然ASP.NET MVC中的Response類型是HttpResponseBase,但是顯式地去調用System.Web.Context.Current.Response.End()結果依舊。通過Reflector查看ASP.NET MVC下HttpResponseBase的實現類HttpResponseWrapper,End方法的實現如圖,this_httpResponse是HttpResponse的私有變量。
查到這兒思路一度中斷,只好回頭去對比調試信息中的表現,從ThreadAbortException這個異常入手,發現在ASP.NET MVC中先調用Response.End(),再調用Thread.CurrentThread.Abort()可以達到webform下調用Response.End()的效果。當然其他異常也能模擬,但是此時發現了一個小問題,就是拋出普通異常的時候和拋出ThreadAbortException異常略有不同。
webform和mvc的區別,普通異常的彈出窗口:
調試信息輸出:
ThreadAbortException異常沒有彈出那個窗口,調試信息中也多了一條信息。
前端foreach用法、
是由于ThreadAbortException是SystemException(系統異常)被特殊對待了嗎?
這只是一個衍生出來的疑問,繼續剛才的問題,用ThreadAbortException和ASP.NET MVC作為關鍵字去google搜索,在Will保哥的博客中得到了解答!
具體可以參見這篇博客下的評論和另一篇博客。
mvc請求流程,經過保哥的指點,通過Reflector去查看源碼,證實了是_timeoutState的作用。
HttpResponse.End中代碼:
IsInCancellablePeriod屬性:
問題得到了解決!~但是我還有一個小疑問,也就是從Reflector中看到End方法的源碼,IsInCancellablePeriod是bool類型,但是卻判斷是否等于null。這怎么也是不合適的吧,是Reflector的解析錯誤還是其他原因導致的呢?