¿Por qué Response.Redirect provoca System.Threading.ThreadAbortException?
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.Redirect
que 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.Redirect
o hay alguna manera de forzar que la página anterior deje de cargarse y no obtendré un mensaje de correo electrónico ThreadAbortException
?
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.
No existe una solución simple y elegante al Redirect
problema 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 ThreadAbortedException
para 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, ThreadAbortedExceptions
aparecerá 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 CompleteRequest
indica 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 RedirectAction
en el controlador, sin generar una vista.
Sé que llego tarde, pero solo he recibido este error si estoy Response.Redirect
en un Try...Catch
bloque.
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.
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.
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.
}
}
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.
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)