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

时间:2009-07-06 15:58:29

标签: .net asp.net

This KB Article说ASP.NET的Response.End()中止了一个帖子。

Reflector显示它看起来像这样:

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()之后的应用程序中的任何代码都不会被执行,这违反了最不惊讶的原则。它几乎像WinForms应用程序中的Application.Exit()Response.End()导致的线程中止异常无法捕获,因此围绕try ... finally中的代码将无法满足。

这让我想知道我是否应该总是避免Response.End()

Response.End()Response.Close()时,有人可以建议何时使用HttpContext.Current.ApplicationInstance.CompleteRequest()

参考:Rick Strahl's blog entry


根据我收到的输入,我的答案是,是的,Response.End是有害的,但在某些有限的情况下它很有用。

  • 使用Response.End()作为无法捕获的投掷,以便在异常情况下立即终止HttpResponse。在调试过程中也很有用。 避免Response.End()完成例行回复
  • 使用Response.Close()立即关闭与客户端的连接。根据{{​​3}},此方法不适用于正常的HTTP请求处理。您不太可能有充分理由调用此方法。
  • 使用CompleteRequest()结束正常请求。当前CompleteRequest事件完成后,EndRequest会导致ASP.NET管道跳转到HttpApplication事件。因此,如果您调用CompleteRequest,然后将更多内容写入响应,则写入将发送到客户端。

编辑 - 2011年4月13日

此处可提供更清晰的信息:
- this MSDN blog post
- Useful post on MSDN Blog

9 个答案:

答案 0 :(得分:105)

TL; DR

  

最初我曾建议您只需将所有来电替换为   [Response.End]与[...] CompleteRequest()调用,但如果你想避免   回发处理和html渲染,你需要添加[...]覆盖   好。

     

Jon Reid,“最终分析”


每个MSDN,Jon Reid和Alain Renon:

ASP.NET Performance - Exception Management - Write Code That Avoids Exceptions

  

Server.Transfer,Response.Redirect,Response.End方法全部引发   例外。这些方法中的每一个都在内部调用Response.End。打电话给   Response.End,反过来,causes a ThreadAbortException exception

ThreadAbortException Solution

  

HttpApplication.CompleteRequest()设置一个导致线程的变量   跳过HttpApplication事件管道中的大多数事件[ - ]而不是   页面事件链,但是应用程序事件链。

     

...

     

创建一个类级别变量,标记页面是否应该终止然后   在处理事件或呈现页面之前检查变量。 [...]   我建议只overriding the RaisePostBackEvent and Render methods

当正常的请求处理时,Response.End和Response.Close不被使用 表现很重要。 Response.End是一种方便,严厉的手段 终止请求处理以及相关的性能损失。 Response.Close用于在IIS /套接字上立即终止HTTP响应 等级并导致KeepAlive之类的问题。

结束ASP.NET请求的推荐方法是 HttpApplication.CompleteRequest。请记住,ASP.NET渲染将具有 由于HttpApplication.CompleteRequest跳过剩下的部分,因此要手动跳过 IIS / ASP.NET应用程序管道,而不是ASP.NET页面管道(即 应用程序管道中的一个阶段。)


代码

Copyright © 2001-2007, C6 Software, Inc我能说得最清楚。


参考

HttpApplication.CompleteRequest

  

使ASP.NET绕过HTTP管道链中的所有事件和过滤   执行并直接执行EndRequest事件。

Response.End

  

此方法仅提供与ASP的兼容性 - 即for   与先前基于COM的Web编程技术的兼容性   ASP.NET.preceded ASP.NET。 [强调补充]

Response.Close

  

此方法以突然方式终止与客户端的连接   不适用于正常的HTTP请求处理。 [强调补充]

答案 1 :(得分:94)

此问题出现在所有谷歌搜索的顶部附近有关response.end的信息,因此对于像我这样的其他搜索,如果希望发布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()

答案 2 :(得分:63)

如果您在自己的应用中使用了异常记录器,则会使用这些良性ThreadAbortException来电中的Response.End()对其进行淡化。我认为这是微软的说法“敲掉它!”。

如果有一些异常情况并且没有其他可能的行动,我只会使用Response.End()。也许那时,记录此异常实际上可能表示警告。

答案 3 :(得分:11)

关于“我仍然不知道Response.Close和CompleteRequest()之间的区别”我会说:

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

有关此案例的完善摘要,请参阅following article

请注意,即使在调用CompleteRequest()之后,某些文本(例如,从ASPX代码重新编译)也会附加到响应输出流中。您可以通过覆盖following article中所述的Render和RaisePostBackEvent方法来阻止它。

BTW:我同意阻止使用Response.End(),特别是在将数据写入http流以模拟文件下载时。我们过去曾使用过Response.End(),直到我们的日志文件充满了ThreadAbortExceptions。

答案 4 :(得分:9)

我不同意声明“ Response.End is harm ”。这绝对没有害处。 Response.End做它说的话;它结束了页面的执行。使用反射器来查看它的实现方式只应被视为具有指导性。


我的2cent建议书 避免使用Response.End()作为控制流 DO 如果您需要停止请求执行,请使用Response.End()并注意(通常)*没有代码会在该点之后执行。


* Response.End()ThreadAbortException s。

Response.End()抛出一个ThreadAbortException作为其当前实现的一部分(如OP所述)。

  

ThreadAbortException是一个可以捕获的特殊异常,但是   它将在catch块结束时自动再次提升。

要了解如何编写必须处理ThreadAbortExceptions的代码,请参阅@ Mehrdad对SO How can I detect a threadabortexception in a finally block的回复,其中他引用了RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup MethodConstrained Execution Regions


提到的Rick Strahl article具有指导意义,请务必阅读评论。请注意,Strahl的问题是具体的。他希望将数据传输到客户端(图像),然后处理命中跟踪数据库更新,这不会减慢图像的服务速度,这使他在调用Response.End后做了一些事情。< / p>

答案 5 :(得分:4)

我从未考虑过使用Response.End()来控制程序流程。

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

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

答案 6 :(得分:2)

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

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

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

答案 7 :(得分:2)

我只使用Response.End()作为测试/调试机制

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

根据您在研究方面发布的内容,我认为如果需要Response.End

那将是一个糟糕的设计。

答案 8 :(得分:0)

在经典的asp上,在一些ajax调用中,我的TTFB(第一个字节的时间)为3到10秒,比在具有更多SQL调用的常规页面上的TTFB大得多。

返回的ajax是一段要注入到页面中的HTML。

TTFB比渲染时间长几秒钟。

如果我在渲染后添加了response.end,则TTFB大大减少了。

我可以通过发出“ ”来获得相同的效果,但是在输出json或xml时这可能不起作用;这里需要response.end。