¿Por qué Response.Redirect provoca System.Threading.ThreadAbortException?

Resuelto Ben Hoffman asked hace 14 años • 10 respuestas

Cuando uso Response.Redirect(...) para redirigir mi formulario a una nueva página, aparece el error:

Se produjo una excepción de primera oportunidad de tipo 'System.Threading.ThreadAbortException' en mscorlib.dll.
Se produjo una excepción de tipo 'System.Threading.ThreadAbortException' en mscorlib.dll pero no se manejó en el código de usuario.

Según tengo entendido, el error se debe a que el servidor web canceló el resto de la página en la que se invocó la respuesta.redirect.

Sé que puedo agregar un segundo parámetro Response.Redirectque se llama endResponse. Si configuro endResponse en Verdadero, sigo recibiendo el error, pero si lo configuro en Falso, entonces no. Sin embargo, estoy bastante seguro de que eso significa que el servidor web está ejecutando el resto de la página desde la que redirigí. Lo cual parecería, cuanto menos, ineficiente. ¿Hay una mejor manera de hacer esto? ¿Algo más que Response.Redirecto hay alguna manera de forzar que la página anterior deje de cargarse y no obtendré un mensaje de correo electrónico ThreadAbortException?

Ben Hoffman avatar May 06 '10 05:05 Ben Hoffman
Aceptado

El patrón correcto es llamar a la sobrecarga de redireccionamiento con endResponse=false y realizar una llamada para indicarle a la canalización de IIS que debe avanzar directamente a la etapa EndRequest una vez que devuelva el control:

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

Esta publicación de blog de Thomas Marquardt proporciona detalles adicionales, incluido cómo manejar el caso especial de redireccionamiento dentro de un controlador Application_Error.

Joel Fillmore avatar May 05 '2010 22:05 Joel Fillmore

No existe una solución simple y elegante al Redirectproblema en ASP.Net WebForms. Puedes elegir entre la solución Sucia y la solución Tediosa

Sucio : Response.Redirect(url)envía una redirección al navegador y luego lanza un ThreadAbortedExceptionpara finalizar el hilo actual. Por lo tanto, no se ejecuta ningún código más allá de la llamada Redirect(). Desventajas: Es una mala práctica y tiene implicaciones de rendimiento eliminar subprocesos como este. Además, ThreadAbortedExceptionsaparecerá en el registro de excepciones.

Tedioso : la forma recomendada es llamar Response.Redirect(url, false)y luego Context.ApplicationInstance.CompleteRequest(). Sin embargo, la ejecución del código continuará y el resto de los controladores de eventos en el ciclo de vida de la página aún se ejecutarán. (Por ejemplo, si realiza la redirección en Page_Load, no solo se ejecutará el resto del controlador, sino que también se llamará a Page_PreRender, etc.; la página renderizada simplemente no se enviará al navegador. Puede evitar el procesamiento adicional si por ejemplo, establecer una bandera en la página y luego dejar que los controladores de eventos posteriores verifiquen esta bandera antes de realizar cualquier procesamiento.

(La documentación CompleteRequestindica que " Hace que ASP.NET omita todos los eventos y filtros en la cadena de ejecución de la canalización HTTP ". Esto puede malinterpretarse fácilmente. Omite más filtros y módulos HTTP, pero no omite más eventos. en el ciclo de vida de la página actual ).

El problema más profundo es que WebForms carece de un nivel de abstracción. Cuando estás en un controlador de eventos, ya estás en el proceso de crear una página para generar. Redirigir en un controlador de eventos es feo porque estás finalizando una página parcialmente generada para generar una página diferente. MVC no tiene este problema ya que el flujo de control está separado de las vistas de renderizado, por lo que puede realizar una redirección limpia simplemente devolviendo a RedirectActionen el controlador, sin generar una vista.

JacquesB avatar Oct 18 '2012 15:10 JacquesB

Sé que llego tarde, pero solo he recibido este error si estoy Response.Redirecten un Try...Catchbloque.

Nunca coloques un Response.Redirect en un bloque Try...Catch. es una mala practica

Como alternativa a colocar Response.Redirect en el bloque Try...Catch, dividiría el método/función en dos pasos.

  1. dentro del bloque Try...Catch realiza las acciones solicitadas y establece un valor de "resultado" para indicar el éxito o el fracaso de las acciones.

  2. fuera del bloque Try...Catch realiza la redirección (o no) dependiendo de cuál sea el valor del "resultado".

Este código está lejos de ser perfecto y probablemente no debería copiarse ya que no lo he probado .

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.
    }
}
Ortund avatar Jun 28 '2012 06:06 Ortund

Response.Redirect()lanza una excepción para abortar la solicitud actual.

Este artículo de KB describe este comportamiento (también para los métodos Request.End()y Server.Transfer()).

Porque Response.Redirect()existe una sobrecarga:

Response.Redirect(String url, bool endResponse)

Si pasa endResponse=false , entonces no se lanza la excepción (pero el tiempo de ejecución continuará procesando la solicitud actual).

Si endResponse=true (o si se usa otra sobrecarga), se lanza la excepción y la solicitud actual finalizará inmediatamente.

M4N avatar May 05 '2010 22:05 M4N

Aquí está la línea oficial sobre el problema (no pude encontrar la última, pero no creo que la situación haya cambiado para versiones posteriores de .net)

spender avatar May 05 '2010 22:05 spender