在Response.RedirectToRoute之后跳过页面执行的正确方法

Mic*_*son 8 vb.net asp.net webforms response.redirect user-experience

我正在使用新的路由功能编写asp.net 4.5应用程序.我有一个页面显示有关项目的一些信息.在Page_Load事件中,我检查路由数据(项目ID)和用户权限,如果事情是不正确(如ID是删除项),我用Response.RedirectToRoute送他们包装,马上回主页.不要通过GO,不要收200美元.

这是完全合理的,直到我尝试访问已删除的项目,而不是主页,我得到一个错误页面.我做了一些挖掘,发现即使在我使用之后RedirectToRoute(与标准Redirect方法不同),页面代码的其余部分仍继续执行,这至少看起来很浪费(因为我只是要扔掉结果)并抛出错误当必要的数据不存在时.

我做了一些更使挖掘和发现令人难以置信的邪恶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
Run Code Online (Sandbox Code Playgroud)

Vin*_*ayC 10

RedirectToRoute实际上是包装Response.Redirect传递false以结束请求 - 因此,请求继续.您可以使用HttpApplication.CompleteRequest作为立即调用来终止请求,以便不会调用下一个应用程序事件.

Response.End(以及其他重定向变体)抛出ThreadAbortException中止请求处理线程,这实际上是一种停止请求处理的方法.在.NET世界中,异常处理总是被认为是昂贵的,因为CLR然后需要一直向上搜索堆栈以寻找异常处理块,创建堆栈跟踪等.CompleteRequest在.NET 1.1中引入IMO 以避免实际依赖于它的相同在ASP.NET基础结构代码中设置标志以跳过除EndRequest事件之外的进一步处

另一种(更好的)方法是使用Server.Transfer并避免客户端往返以将重定向设置在一起.唯一的问题是客户端不会在浏览器地址栏中看到重定向的URL.我通常更喜欢这种方法.

编辑
CompleteRequest将永远不会在页面情况下工作,其中后续页面事件仍将被调用,因为页面是处理程序,其所有事件都发生在单个(和当前)应用程序事件中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
}
Run Code Online (Sandbox Code Playgroud)

  • @probackpacker,请接受我的道歉!`CompleteRequest`影响应用程序管道事件,但当前处理程序事件将继续.除了使用标志在页面内进行检查之外没有其他方法 - 从维护角度来看,您可以将其提取到可重用的基页类中(请参阅我的编辑). (2认同)

sec*_*wep 3

我可能会因为不直接回答问题而陷入困境,但我喜欢看到您有关用户体验的更新。我更喜欢你建议的方法。

我喜欢对无效的 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
Run Code Online (Sandbox Code Playgroud)