Coder Perfect

Why Response.Redirect causes System.Threading.ThreadAbortException?

Problem

I receive the following issue when I use Response.Redirect(…) to redirect my form to a new page:

According to my understanding, the issue is generated by the webserver aborting the remainder of the page on which the response.redirect was called.

I’m aware that I can extend Response with a second argument. endResponse is the name of the redirect. I still receive the issue if I set endResponse to True, but not if I set it to False. But I’m pretty sure it means the webserver is handling the rest of the page I was routed to. Which, to say the least, appears inefficient. Is there a more efficient method to accomplish this? Response is not the only option. Is there a way to force the old page to cease loading without getting a ThreadAbortException if I redirect?

Asked by Ben Hoffman

Solution #1

The right approach is to call the Redirect overload with endResponse=false and then make a call to inform the IIS pipeline to go straight to the EndRequest stage once control is returned:

Response.Redirect(url, false);
Context.ApplicationInstance.CompleteRequest();

Additional information, including how to handle the unusual scenario of redirecting inside an Application Error handler, may be found in this blog article by Thomas Marquardt.

Answered by Joel Fillmore

Solution #2

In ASP.Net WebForms, there is no straightforward and elegant solution to the Redirect problem. You have the option of choosing between the Dirty and the Tedious solutions.

‘Dirty’ is the response. Redirect(url) sends a redirect to the browser before terminating the current thread with a ThreadAbortedException. As a result, no code is run after the call to Redirect(). Downsides: Killing threads like this is bad practice and has performance concerns. ThreadAbortedExceptions will also be logged in the exception log.

Calling Response is the recommended method. Context, then Redirect(url, false). ApplicationInstance. CompleteRequest() However, code execution will continue, as will the execution of the remaining event handlers in the page lifecycle. (For example, if you do the redirect in Page Load, not only will the rest of the handler be executed, but so will Page PreRender and so on – the rendered page will just not be given to the browser.) You can avoid additional processing by, for example, placing a flag on the page and allowing subsequent event handlers to verify this flag before conducting any processing.

(According to the documentation, CompleteRequest “causes ASP.NET to bypass all events and filtering in the HTTP pipeline chain of execution.”) This is readily misinterpreted. It bypasses additional HTTP filters and modules, but not further events in the current page lifecycle.)

The deeper issue is that WebForms lacks an abstraction level. When you’re in an event handler, you’re already working on creating a page to display. Because you’re terminating a partially formed page in order to generate an alternative page, redirecting in an event handler is unsightly. Because the control flow and displaying views are separated in MVC, you can make a clean redirect by simply returning a RedirectAction in the controller rather than producing a view.

Answered by JacquesB

Solution #3

I realize I’m late, but this problem has only ever occurred when I’ve submitted a Response. Redirect is in the process of being tested… This is a catch block.

Never, ever, ever, ever, ever, ever, ever, ever, ever, ever Replace the redirect with a Try…Catch block. It’s unethical.

I’d split the method/function into two parts instead of putting the Response.Redirect into the Try…Catch block.

Because I haven’t tried it, this code is far from ideal and shouldn’t be copied.

public void btnLogin_Click(UserLoginViewModel model)
{
    bool ValidLogin = false; // this is our "result value"
    try
    {
        using (Context Db = new Context)
        {
            User User = new User();

            if (String.IsNullOrEmpty(model.EmailAddress))
                ValidLogin = false; // no email address was entered
            else
                User = Db.FirstOrDefault(x => x.EmailAddress == model.EmailAddress);

            if (User != null && User.PasswordHash == Hashing.CreateHash(model.Password))
                ValidLogin = true; // login succeeded
        }
    }
    catch (Exception ex)
    {
        throw ex; // something went wrong so throw an error
    }

    if (ValidLogin)
    {
        GenerateCookie(User);
        Response.Redirect("~/Members/Default.aspx");
    }
    else
    {
        // do something to indicate that the login failed.
    }
}

Answered by Ortund

Solution #4

Response. The current request is aborted when Redirect() raises an error.

This behavior (as well as the Request.End() and Server.Transfer() methods) is described in this KB article.

There is an overload for Response.Redirect():

Response.Redirect(String url, bool endResponse)

If you specify endResponse=false, the exception will not be thrown (but the runtime will continue processing the current request).

The exception is issued and the current request is instantly canceled if endResponse=true (or if the other overload is used).

Answered by M4N

Solution #5

Here’s Microsoft’s official statement on the issue (I couldn’t find the most recent, but I don’t believe the situation has altered for subsequent versions of.net).

Answered by spender

Post is based on https://stackoverflow.com/questions/2777105/why-response-redirect-causes-system-threading-threadabortexception