10

We had a problem recently where one of the developers had changed a line of code from using HttpResponse.End to using HttpApplication.CompleteRequest when forcing a PDF to download in a similar fashion to the following: https://stackoverflow.com/a/8590579/3856039

Doing so caused some PDF's to fail to download due to a non-breaking space issue so the code was changed back to using HttpResponse.End.

However, in helping my colleague I was carrying out some research and I came across the following question: Is Response.End() considered harmful?

Which links to: https://blogs.msdn.microsoft.com/aspnetue/2010/05/25/response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation/

Given what is documented in the MSDN blog post, it sounds like using HttpResponse.End is the wrong approach, so I was wondering if it is even needed or whether there is a better approach?

Community
  • 1
  • 1
Professor of programming
  • 2,978
  • 3
  • 30
  • 48
  • If you have a reason to manually terminate the request then CompleteRequest is the thing to use, if this is causing a problem elsewhere then thats what you should address and fix. You don't need to call anything if your application naturally unwinds back to its entry point after the response is written. – Alex K. Jul 22 '16 at 15:47
  • Have you tried to read the file as byte array and return it as a FileResult? It does not respond to your question, but it could be a workaround. – Florin V Jul 28 '16 at 07:53
  • I think the MSDN link that you included has the answer you're looking for: "The End method is only there because we tried to be compatible with classic ASP when 1.0 was released." It then goes on to say that it's not recommended because it flushes the content synchronously, whereas the data is sent asynchronously if the request ends in the usual manner. "The documentation for End should state that CompleteRequest is a better way to skip ahead to the EndRequest notification and complete the request." – Ade Stringer Aug 01 '16 at 15:03

2 Answers2

1

Here is the actual code from Response.End:

public void End()
{
    if (this._context.IsInCancellablePeriod)
    {
        HttpResponse.AbortCurrentThread();
        return;
    }
    this._endRequiresObservation = true;
    if (!this._flushing)
    {
        this.Flush();
        this._ended = true;
        if (this._context.ApplicationInstance != null)
        {
            this._context.ApplicationInstance.CompleteRequest();
        }
    }
}

The ThreadAbortException is used for control of flow-- basically allowing you to use Response.End in place of return. But if you've designed your handler well, you may not need it, e.g. if there is no code after Response.End(). It is generally better not to throw the exception if you can avoid it, since it (like all exceptions) will cause a stack unwind and some performance overhead.

Perhaps you can write your own version of Response.End and pick and choose which lines of code actually execute, e.g. maybe you want to flush the buffer and call CompleteRequest but you don't want to throw the exception.

John Wu
  • 50,556
  • 8
  • 44
  • 80
0

Here is the approach I have used in the past

// Sends all currently buffered output 
HttpContext.Current.Response.Flush(); to the client.

// Gets or sets a value indicating whether to send HTTP content to the client.
HttpContext.Current.Response.SuppressContent = true;

/* Causes ASP.NET to bypass all events and filtering in the HTTP pipeline 
   chain of execution and directly execute the EndRequest event. */
HttpContext.Current.ApplicationInstance.CompleteRequest(); 
Tasos K.
  • 7,979
  • 7
  • 39
  • 63
Paresh
  • 993
  • 1
  • 7
  • 15