在 Response.RedirectToRoute 之後跳過頁面執行的正確方法
我正在使用新的路由功能編寫一個 asp.net 4.5 應用程序。我有一個頁面顯示有關項目的一些資訊。如果
Page_Load我檢查路線數據(項目 id)和使用者權限,如果有什麼不對勁(例如,id 是一個已刪除的項目),我會用Response.RedirectToRoute它們打包,直接返回首頁。不要通過 GO,不要收取 200 美元。直到我嘗試訪問已刪除的項目並且我得到一個錯誤頁面而不是首頁,這才完全有意義。我做了一些探勘,發現即使在我使用之後
RedirectToRoute(與標準Redirect方法不同),頁面的其餘部分程式碼仍在繼續執行,這至少看起來很浪費(因為我只是要扔掉結果)並拋出錯誤當必要的數據不存在時。我做了更多的 SO 探勘,發現了令人難以置信的邪惡
Response.End()。它可以滿足我的需要,但即使是 MSDN頁面也告訴我這Response.End是一種古老的被詛咒語言的私生子,不適合看到光明。主要的反對意見似乎是 Response.End 拋出異常,這對性能不利。我不是最有經驗的開發人員,所以我不完全理解這個問題,但我很難相信拋出異常比載入整個網頁更昂貴。對於如此簡單的任務,變通方法似乎相當複雜和過度,尤其是因為大多數頁面都需要某種有效性檢查。在這種情況下我該怎麼辦?為我的無禮而使用
Response.End並乞求寬恕?拼湊一些醜陋的解決方法?還是我對這個問題的看法一開始就錯了?我真的很想知道。更新:現在我已經考慮了更多,我想知道我是否對這個問題有錯誤的看法。也許立即重定向並不是使用者體驗的最佳響應。將所有控制項包裝在面板中並使用類似的東西會更好嗎?
Private Sub Page_Init(sender As Object, e As EventArgs) Handles Me.Init 'Validation Code If notValid Then ControlsPanel.Visible = false ErrorPanel.Visible = true End If End Sub
我可能會因為不直接回答問題而陷入困境,但我喜歡看到你關於使用者體驗的更新。我更喜歡你建議的方法。
我喜歡為無效的 id 提供 410 錯誤,並使用(從 C# 翻譯)對其進行擴展:
Protected Sub ItemDoesNotExist() 'item does not exist, serve up error page ControlsPanel.Visible = False ErrorPanel.Visible = True 'add meta tags for noindex Dim mymeta As New HtmlMeta() mymeta.Name = "robots" mymeta.Content = "noindex" Page.Header.Controls.Add(mymeta) 'RESPOND WITH A 410 Response.StatusCode = 410 Response.Status = "410 Gone" Response.StatusDescription = "Gone" Response.TrySkipIisCustomErrors = True 'important for IIS7, otherwise the Custom error page for 404 shows. Page.Title = "item gone" End Sub
RedirectToRoute實際上包裝了Response.Redirect傳遞
false以結束請求 - 因此,請求繼續。您可以使用HttpApplication.CompleteRequest作為立即呼叫來終止請求,以便不會呼叫下一個應用程序事件。
Response.End(和其他重定向變體)拋出ThreadAbortException以中止請求處理執行緒,這確實是停止請求處理的*不好方法。*在 .NET 世界中,異常處理總是被認為是昂貴的,因為 CLR 然後需要一直向上搜尋堆棧以查找異常處理塊、創建堆棧跟踪等。IMOCompleteRequest在 .NET 1.1 中被引入以避免實際依賴的相同在 ASP.NET 基礎結構程式碼中設置標誌以跳過除EndRequest事件之外的進一步處理。另一種(更好的)方法是使用Server.Transfer並避免客戶端往返以一起設置重定向。唯一的問題是客戶端不會在瀏覽器地址欄中看到重定向的 URL。我通常更喜歡這種方法。
EDIT
CompleteRequest永遠不會在頁面情況下工作,因為 page 是一個處理程序,後續頁面事件仍然會被呼叫,它的所有事件都發生在單個(和目前)應用程序事件中ProcessRequest。因此,唯一的方法似乎是設置一個標誌並在諸如 , 等覆蓋中檢查Render該PreRender標誌RaisePostBackEvent。從維護的角度來看,在基頁麵類中具有這樣的功能是有意義的(即維護標誌、為
CompleteRequest子類提供方法和覆蓋生命週期事件方法)。例如,internal class PageBase: System.Web.UI.Page { bool _requestCompleted; protected void CompleteRequest() { Context.ApplicationInstance.CompleteRequest(); _requestCompleted = true; } protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument) { if (_requestCompleted) return; base.RaisePostBackEvent(sourceControl, eventArgument); } protected internal override void Render(HtmlTextWriter writer) { if (_requestCompleted) return; base.Render(writer); } protected internal override void OnPreRender(EventArgs e) { if (_requestCompleted) return; base.OnPreRender(e); } ... and so on }