Response.End()被认为是有害的吗?

这个知识库文章说,ASP.NET的Response.End()中止一个线程。

reflection器显示它看起来像这样:

 public void End() { if (this._context.IsInCancellablePeriod) { InternalSecurityPermissions.ControlThread.Assert(); Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false)); } else if (!this._flushing) { this.Flush(); this._ended = true; if (this._context.ApplicationInstance != null) { this._context.ApplicationInstance.CompleteRequest(); } } } 

这对我来说似乎相当苛刻。 正如知识库文章所述,应用程序中的任何代码在Response.End()都不会被执行,这违反了最less惊讶的原则。 这几乎就像WinForms应用程序中的Application.Exit() 。 由Response.End()引起的线程exceptionexception是不可捕获的,所以在try …中围绕代码… finally不会满足。

这让我怀疑我是否应该总是避免Response.End()

任何人都可以提出,什么时候应该使用Response.End() ,何时Response.Close()和何时HttpContext.Current.ApplicationInstance.CompleteRequest()

参考: Rick Strahl的博客条目 。


根据我收到的意见,我的回答是, 是的, Response.End是有害的 ,但在一些有限的情况下是有用的。

  • 使用Response.End()作为不可捕获的抛出,在特殊情况下立即终止HttpResponse 。 也可以在debugging时使用。 避免Response.End()来完成例程响应
  • 使用Response.Close()立即closures与客户端的连接。 根据此MSDN博客文章 ,此方法不适用于正常的HTTP请求处理。 你很可能有一个很好的理由来调用这个方法。
  • 使用CompleteRequest()来结束一个正常的请求。 在当前的HttpApplication事件完成之后, CompleteRequest会导致ASP.NETpipe道跳转到EndRequest事件。 所以,如果你调用CompleteRequest ,然后写更多的东西给响应,写将被发送到客户端。

编辑 – 2011年4月13日

更进一步的清晰度可在这
– MSDN博客上有用的文章
– Jon Reid的有用分析

如果您在应用程序中使用了exceptionlogging器,则会从这些良性的Response.End()调用中使用ThreadAbortException来淡化。 我认为这是微软说的“敲掉它”的方式。

我只会使用Response.End()如果有一些例外情况,并没有其他的行动是可能的。 也许呢,logging这个exception可能实际上表明一个警告。

TL; DR

最初,我build议你只需用[…] CompleteRequest()调用将所有的调用replace为[Response.End],但如果你想避免回发处理和HTML渲染,你需要添加[..] 。]覆盖以及。

Jon Reid ,“最终分析”


按照MSDN, Jon Reid和Alain Renon的说法:

ASP.NET性能 – exceptionpipe理 – 编写避免exception的代码

Server.Transfer,Response.Redirect,Response.End方法都引发exception。 每个这些方法在内部调用Response.End。 对Response.End的调用反过来会导致ThreadAbortExceptionexception 。

ThreadAbortException解决scheme

HttpApplication.CompleteRequest()设置一个variables,使线程跳过HttpApplication事件pipe道中的大部分事件[ – ]而不是页面事件链,而是应用程序事件链。

创build一个类级variables来标记页面是否应该终止,然后在处理事件或呈现页面之前检查variables。 […]我会build议只是重写RaisePostBackEvent和渲染方法

当性能很重要时,Response.End和Response.Close不用于正常的请求处理。 Response.End是一个方便,严格的手段,终止请求处理,并有相关的性能损失。 Response.Close用于立即终止IIS /套接字级别的HTTP响应,并导致KeepAlive等问题。

推荐的结束ASP.NET请求的方法是HttpApplication.CompleteRequest。 请记住,由于HttpApplication.CompleteRequest会跳过IIS / ASP.NET应用程序pipe道的其余部分,而不是ASP.NET页面pipe道(这是应用程序pipe道中的一个阶段),因此必须手动跳过ASP.NET呈现。


版权所有©2001-2007,C6软件公司尽我所能。


参考

HttpApplication.CompleteRequest

导致ASP.NET绕过执行的HTTPpipe道链中的所有事件和筛选,并直接执行EndRequest事件。

到Response.End

此方法仅用于与ASP兼容,即与ASP.NET.preceded ASP.NET之前的基于COM的Web编程技术兼容。 [强调添加]

Response.Close

该方法以突然的方式终止与客户端的连接, 不用于正常的HTTP请求处理 。 [强调添加]

这个问题出现在所有谷歌search的顶部附近的response.end的信息,所以对于像我这样的其他search谁希望发布CSV / XML / PDF等响应一个事件,而无需呈现整个ASPX页面,这就是我怎么做。 (重写渲染方法对于如此简单的IMO任务来说过于复杂)

 // Add headers for a csv file or whatever Response.ContentType = "text/csv" Response.AddHeader("Content-Disposition", "attachment;filename=report.csv") Response.AddHeader("Pragma", "no-cache") Response.AddHeader("Cache-Control", "no-cache") // Write the data as binary from a unicode string Dim buffer As Byte() buffer = System.Text.Encoding.Unicode.GetBytes(csv) Response.BinaryWrite(buffer) // Sends the response buffer Response.Flush() // Prevents any other content from being sent to the browser Response.SuppressContent = True // Directs the thread to finish, bypassing additional processing HttpContext.Current.ApplicationInstance.CompleteRequest() 

在“我仍然不知道Response.Close和CompleteRequest()之间的区别”的问题上,我会说:

更喜欢CompleteRequest(),不要使用Response.Close()。

请参阅以下文章,以获得有关此案例的完整摘要。

请注意,即使在调用CompleteRequest()之后,一些文本(例如,从ASPX代码重新sorting)也会被添加到响应输出stream中。 您可以通过重写Render和RaisePostBackEvent方法来防止它,如下面的文章中所述 。

顺便说一句:我同意防止使用Response.End(),尤其是当写入数据到HTTPstream模拟文件下载。 过去我们使用了Response.End(),直到我们的日志文件变满了ThreadAbortExceptions。

我不同意“ 响应。结束是有害的 ”的说法。 这绝对没有害处。 Response.End做它说的; 它结束页面的执行。 使用reflection器看它是如何实现的只应该被看作是有启发性的。


我的2centbuild议
避免使用Response.End()作为控制stream。
如果你需要停止请求的执行,请使用Response.End() ,并且要知道(典型情况下)*没有任何代码会在这个点之后执行。


* Response.End()和ThreadAbortException s。

Response.End()将引发ThreadAbortException作为其当前实现的一部分(如OP所述)。

ThreadAbortException是一个特殊的exception,可以被捕获,但是它会在catch块的末尾自动重新引发。

要了解如何编写必须处理ThreadAbortExceptions的代码,请参阅@ Mehrdad对SO的回复如何在finally块中检测 threadabortexception, 在这个块中引用RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup方法和约束执行区


所提到的里克斯特拉尔文章是有启发性的,并确保阅读评论。 请注意,Strahl的问题是具体的。 他想把数据提交给客户端(一张图片),然后处理跟踪数据库更新,这并没有减慢图片的服务速度,这使得他在Response.End被调用之后做了一些事情。

我从来没有考虑过使用Response.End()来控制程序stream。

但是,Response.End()在向用户提供文件时可能很有用。

您已将该文件写入响应,并且您不希望任何其他内容被添加到响应中,因为它可能会损坏您的文件。

我在.NET和Classic ASP中都使用了Response.End()来强制结束之前的事情。 例如,当有一定数量的login尝试时,我使用它。 或者,当一个安全的页面正在接受来自未经身份validation的login(粗略示例):

  if (userName == "") { Response.Redirect("......"); Response.End(); } else { ..... 

当向用户提供文件时,我会使用Flush,End可能会导致问题。

我只使用Response.End()作为testing/debugging机制

 <snip> Response.Write("myVariable: " + myVariable.ToString()); Response.End(); <snip> 

从研究的angular度来看,我认为如果需要Response.End,这将是一个糟糕的devise