¿Response.End () se considera perjudicial?

Este artículo de KB dice que Response.End() ASP.NET anula un hilo.

El reflector muestra que se ve así:

 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(); } } } 

Esto me parece muy duro. Como dice el artículo de KB, cualquier código de la aplicación que siga a Response.End() no se ejecutará, y eso viola el principio de menos asombro. Es casi como Application.Exit() en una aplicación WinForms. La excepción de aborto de hilo provocada por Response.End() no es capturable, por lo que rodear el código en un tryfinally no satisfará.

Me pregunto si siempre debo evitar Response.End() .

¿Alguien puede sugerir, cuándo debería usar Response.End() , cuando Response.Close() y cuando HttpContext.Current.ApplicationInstance.CompleteRequest() ?

ref: entrada del blog de Rick Strahl .


En función de la información que he recibido, mi respuesta es Sí, Response.End es perjudicial , pero es útil en algunos casos limitados.

  • use Response.End() como un lanzamiento imposible de atrapar, para terminar inmediatamente el HttpResponse en condiciones excepcionales. Puede ser útil durante la depuración también. Evite Response.End() para completar las respuestas de rutina .
  • use Response.Close() para cerrar inmediatamente la conexión con el cliente. Según esta publicación de blog de MSDN , este método no está destinado al procesamiento de solicitud HTTP normal. Es muy poco probable que tenga una buena razón para llamar a este método.
  • use CompleteRequest() para finalizar una solicitud normal. CompleteRequest hace que la tubería ASP.NET salte al evento EndRequest , después de que se HttpApplication evento HttpApplication actual. Entonces, si llama a CompleteRequest y luego escribe algo más a la respuesta, la escritura se enviará al cliente.

Edición – 13 de abril de 2011

Más claridad está disponible aquí:
– Publicación útil en MSDN Blog
– Análisis útil por Jon Reid

Si había empleado un registrador de excepciones en su aplicación, se diluirá con las excepciones ThreadAbortException de estas benignas llamadas Response.End() . Creo que esta es la forma en que Microsoft dice “¡No lo hagas!”.

Solo usaría Response.End() si hubiera alguna condición excepcional y no hubiera otra acción posible. Quizás entonces, registrar esta excepción en realidad podría indicar una advertencia.

TL; DR

Inicialmente, le recomendé que simplemente reemplace todas sus llamadas a [Response.End] con llamadas […] CompleteRequest (), pero si desea evitar el procesamiento de devolución de datos y el procesamiento de html, deberá agregar [.. .] también anula.

Jon Reid , “Análisis final”


Por MSDN, Jon Reid y Alain Renon:

Rendimiento ASP.NET – Gestión de excepciones – Código de escritura que evita excepciones

Los métodos Server.Transfer, Response.Redirect, Response.End generan excepciones. Cada uno de estos métodos llama internamente Response.End. La llamada a Response.End, a su vez, causa una excepción ThreadAbortException .

Solución ThreadAbortException

HttpApplication.CompleteRequest () establece una variable que provoca que el subproceso omita la mayoría de los eventos en la interconexión de eventos HttpApplication [-], no en la cadena de eventos de página, sino en la cadena de eventos de la aplicación.

crea una variable de nivel de clase que marque si la Página debe terminar y luego verifica la variable antes de procesar tus eventos o renderizar tu página. […] Yo recomendaría simplemente anular los métodos RaisePostBackEvent y Render

Response.End y Response.Close no se utilizan en el procesamiento de solicitud normal cuando el rendimiento es importante. Response.End es un medio conveniente y pesado para finalizar el procesamiento de solicitudes con una penalización de rendimiento asociada. Response.Close es para la terminación inmediata de la respuesta HTTP en el nivel IIS / socket y causa problemas con cosas como KeepAlive.

El método recomendado para finalizar una solicitud de ASP.NET es HttpApplication.CompleteRequest. Tenga en cuenta que la representación ASP.NET tendrá que omitirse manualmente ya que HttpApplication.CompleteRequest se salta el rest de la interconexión de aplicaciones IIS / ASP.NET, no la interconexión de páginas ASP.NET (que es una etapa en la interconexión de aplicaciones).


Código

Copyright © 2001-2007, C6 Software, Inc lo mejor que pude decir.


Referencia

HttpApplication.CompleteRequest

Hace que ASP.NET evite todos los eventos y el filtrado en la cadena de ejecución de la tubería HTTP y ejecute directamente el evento EndRequest.

Response.End

Este método se proporciona solo para la compatibilidad con ASP , es decir, para la compatibilidad con la tecnología de progtwigción web basada en COM que precedió a ASP.NET.predited ASP.NET. [Énfasis añadido]

Respuesta.Cerrar

Este método finaliza la conexión con el cliente de manera abrupta y no está destinado al procesamiento de solicitud HTTP normal . [Énfasis añadido]

Esta pregunta aparece cerca de la parte superior de todas las búsquedas de Google para obtener información sobre la respuesta. Por lo tanto, para otras búsquedas como yo que desean publicar CSV / XML / PDF, etc. en respuesta a un evento sin representar toda la página ASPX, así es como lo hago . (anulando los métodos de renderizado es demasiado complejo para una tarea tan simple OMI)

 // 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() 

Sobre la pregunta de “Todavía no sé la diferencia entre Response.Close y CompleteRequest ()”, diría:

Prefiere CompleteRequest (), no use Response.Close ().

Vea el siguiente artículo para un resumen bien hecho de este caso.

Tenga en cuenta que incluso después de llamar a CompleteRequest () algún texto (p. Ej., Encriptado desde el código ASPX) se anexará a la secuencia de salida de respuesta. Puede evitarlo anulando los métodos Render y RaisePostBackEvent como se describe en el siguiente artículo .

Por cierto: estoy de acuerdo con la prevención del uso de Response.End (), especialmente cuando escribo datos en la secuencia http para emular la descarga de archivos. Hemos utilizado Response.End () en el pasado hasta que nuestro archivo de registro se llenó de ThreadAbortExceptions.

No estoy de acuerdo con la afirmación ” Respuesta . El final es dañino “. Definitivamente no es dañino. Response.End hace lo que dice; termina la ejecución de la página. Usar el reflector para ver cómo se implementó solo debe verse como instructivo.


Mi recomendación 2cent
EVITE usar Response.End() como flujo de control.
use Response.End() si necesita detener la ejecución de la solicitud y tenga en cuenta que (normalmente) * no se ejecutará ningún código más allá de ese punto.


* Response.End() y ThreadAbortException s.

Response.End() arroja una ThreadAbortException como parte de su implementación actual (como lo señala OP).

ThreadAbortException es una excepción especial que se puede capturar, pero se levantará automáticamente de nuevo al final del bloque catch.

Para ver cómo escribir código que debe tratar con ThreadAbortExceptions, consulte @Mehrdad’s reply to SO ¿Cómo puedo detectar una amenaza threadaborte en un bloque finally donde hace referencia a RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup Method and Restrained Execution Regions


El artículo de Rick Strahl mencionado es instructivo, y asegúrese de leer los comentarios también. Tenga en cuenta que el problema de Strahl fue específico. Quería obtener los datos para el cliente (una imagen) y luego procesar la actualización de la base de datos de seguimiento que no ralentizaba la publicación de la imagen, lo que hacía que su problema fuera algo después de que Response.End había sido llamado.

Nunca consideré usar Response.End () para controlar el flujo del progtwig.

Sin embargo, Response.End () puede ser útil, por ejemplo, para servir archivos a un usuario.

Usted ha escrito el archivo en la respuesta y no desea que se agregue nada más a la respuesta, ya que puede dañar su archivo.

He usado Response.End () tanto en .NET como en ASP clásico para terminar cosas con fuerza antes. Por ejemplo, lo uso cuando hay una cantidad certificada de bashs de inicio de sesión. O cuando se accede a una página segura desde un inicio de sesión no autenticado (ejemplo aproximado):

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

Al servir archivos a un usuario, utilizaría un color, el final puede causar problemas.

Solo he usado Response.End () como un mecanismo de prueba / depuración

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

A juzgar por lo que ha publicado en términos de investigación, diría que sería un mal diseño si requiriera Response.End