8

我正在使用新的路由功能编写一个 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
4

2 回答 2

10

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。因此,唯一的方法似乎是设置一个标志并在诸如 , 等覆盖中检查RenderPreRender标志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
}
于 2013-01-22T05:37:09.997 回答
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
于 2013-05-14T16:45:01.983 回答