我正在使用新的路由功能编写asp.net 4.5应用程序。我有一个页面显示有关项目的一些信息。在Page_Load
事件中,我检查路由数据(项目ID)和用户权限,如果某些内容不正确(例如,id用于删除的项目),我使用Response.RedirectToRoute
发送包装,回到主页。不要通过GO,不要收200美元。
这是完全合理的,直到我尝试访问已删除的项目,而不是主页,我得到一个错误页面。我做了一些挖掘,发现即使我使用RedirectToRoute
(与标准的Redirect
方法不同)页面代码的其余部分continues to execute,这至少看起来很浪费(因为我'我只是要扔掉结果)并在必要的数据不存在时抛出错误。
我做了更多的SO挖掘,发现了令人难以置信的evil Response.End()
。它做了我需要的,但即使是MSDN page告诉我Response.End
是一个古老被诅咒的语言的私生子,不适合看到光明的一天。主要的反对意见似乎是Response.End抛出一个异常,这对性能有害。我不是最有经验的开发人员,所以我完全不了解这个问题,但我很难相信抛出异常比加载整个网页更加昂贵。对于一项如此简单的任务,workarounds似乎相当复杂和过分,特别是因为大多数页面都需要进行某种有效性检查。
在这种情况下我该怎么办?使用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
答案 0 :(得分:10)
RedirectToRoute实际上包裹Response.Redirect传递false
以结束请求 - 因此,请求继续。您可以使用HttpApplication.CompleteRequest作为立即调用来终止请求,以便不会调用下一个应用程序事件。
Response.End
(和其他重定向变体)抛出ThreadAbortException
以中止请求处理线程,这是一种坏方式来停止请求处理。在.NET世界中,异常处理总是被认为是昂贵的,因为CLR需要在异常处理块中一直向上搜索堆栈,创建堆栈跟踪等。在.NET 1.1中引入了IMO CompleteRequest
以避免实际上依赖于在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
}
答案 1 :(得分: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