He escrito un controlador http personalizado. He hecho esta escribiendo una clase que implementa la IHttphandler.

Dentro de esa clase tengo un código como este,

context.Response.Clear();
context.Response.ClearHeaders();
context.Response.AddHeader("Content-Disposition", "attachment;filename=" + attachmentFileName);
context.Response.AddHeader("Content-Length", new FileInfo(downloadFile).Length.ToString());
context.Response.ContentType = GetMimeType(attachmentFileName);
context.Response.TransmitFile(downloadFile);
context.Response.Flush();
context.Response.Close();

De vez en cuando me aparece un error como este,

Exception HttpException The remote host closed the connection The error code is 0x800703E3

O este,

Exception HttpException The remote host closed the connection The error code is 0x80070040

En ambos casos, el seguimiento de la pila es este,

at System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError(Int32 result, Boolean throwOnDisconnect)
at System.Web.Hosting.IIS7WorkerRequest.ExplicitFlush()
at System.Web.HttpResponse.Flush(Boolean finalFlush)
at System.Web.HttpResponse.Flush()

Esto ocurre en la producción, y si miro hacia atrás en los últimos días se han producido errores 23 veces, y en total el código anterior se ha llamado 497 veces.

Sospecho que este error se refiere a que el usuario haga clic en el vínculo para iniciar el código de arriba más de una vez (que les dará varios cuadros de diálogo de descarga), en la cancelación de algunos de ellos. Después de haber dicho que si era algo como que yo habría esperado que la conexión se cierre correctamente en ambos extremos.

Cómo puedo probar la causa exacta de este error? He probado a habilitar .RED de seguimiento de como esta ¿Por qué no escuchas de seguimiento de registro personalizado de controlador de tráfico? pero no podía llegar a trabajar.

Lo que he encontrado es que aunque me han permitido seguimiento de IIS para registro de solicitudes con error. El fallo se produjo de nuevo, y no había NADA en ese registro.

Cualquier otro trazado puedo permitir, por ejemplo?

La siguiente cosa que probé fue este,

if (context.Response.IsClientConnected)
{
    context.Response.Flush();
    context.Response.Close();
}
else
{
    LogMessage("Client has disconnected before flush was called", Severity.Information);
}

Pero eso no hace ninguna diferencia. La razón aunque supongo que es que el cliente se desconecta mientras que la descarga estaba teniendo lugar, no sin antes vaciar fue llamado.

  • La línea que hace el error ocurre, exactamente?
  • contexto.Respuesta.Flush();
InformationsquelleAutor peter | 2011-04-03

7 Comentarios

  1. 14

    Llevará a cabo tanto la Flush() y Close() llamada. Usted realmente no necesita. Una vez que el controlador está hecho, voy a salir, y ASP.NET se manija de cierre de la solicitud.

    Además, Flush() debe ser utilizado cuando usted está en streaming de contenido para el cliente (añadir partes a la secuencia de respuesta en bloques). No es necesario utilizarlo con TransmitFile().

    • OK, muy interesante. Voy a darle una oportunidad. Gracias.
    • Pero pensando en esto, es que sólo se va a ‘ocultar’ el problema? Si el cierre de la petición hace un HttpException no voy a tener una visibilidad de la que más.
    • Yo ahora recuerdo por qué me requieren la descarga. Es como este, stackoverflow.com/questions/2275894/… si yo no lo llamo el color de mi código elimina el archivo temporal que está siendo descargado, y se puede eliminar es demasiado temprano.
    • si estás generando el archivo, a continuación, usted debe buscar en una forma de generar el contenido y la secuencia para el cliente sin necesidad de guardar en disco. Aparte de eso, usted puede buscar a dejar el archivo temporal en el lugar y, a continuación, utilizando un subproceso de fondo independientes/proceso para eliminar los archivos en un horario.
    • OK, voy a probar eso. ¿Qué acerca de mi segundo comentario, no ‘se va a ocultar el problema’?
    • No estoy convencido de que no hay ningún problema en absoluto. Una excepción no significa necesariamente que hay un problema. Estamos hablando de una red de excepción cuando un cliente se desconecta (gran cosa), y un hilo de anulación de excepción cuando una solicitud se fuerza finalizado (en espera).
    • OK, solo estoy siendo pesimista, recordando que este sistema está en producción. He eliminado la necesidad de guardar el archivo localmente en el servidor web como usted sugiere, y también se elimina el Flush() y Close(). Voy a probarlo en la producción, para ver cómo va.
    • bueno, los desarrolladores deben siempre ser pesimista. Lo mejor para los desarrolladores a pensar en todas las cosas que pueden ir mal antes que ellos. Necesitamos un poco de equilibrio entre el pesimismo y el realismo, aunque. 🙂

  2. 4

    Uso Response.End() en lugar de Response.Flush()

    Esto es lo que el código fuente para Response.End() parece:

    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();
            }
        }
    }
    • Hmmm, no estoy seguro acerca de esto. Cuando yo uso la Respuesta.End() se lanza una excepción de anulación de subprocesos y todo lo demás se convierte para el flan.
    • lanzar una ThreadAbortException es exactamente lo que Response.End() está diseñado para hacer. Esta excepción no debe causar otros problemas.
    • OK, así que usted está diciendo es una buena idea utilizar la Respuesta.End() o no?
    • es una buena idea si usted necesita para terminar una solicitud en el centro de procesamiento por alguna razón. Si usted tiene un controlador dedicado que hace una cosa y alcanza el fin de su natural procesamiento, usted no necesita hacer nada, acaba de regresar de su controlador. Si usted tiene una razón para llamar a Response.End(), sí, va a lanzar una ThreadAbortException, pero no, eso no debe ser considerado un problema.
    • el ThreadAbortException se maneja en la ASP.NET canalización, de modo Response.End() efectivamente va a enviar el HttpResponse y cancelación al tratamiento de cualquiera de código que podría ocurrir después de la llamada.
  3. 2

    Qué .NET framework estás usando? Este hilo del foro aquí describe un problema similar utilizando con IIS7 .NET2.0 específicamente con el cliente desconecte, un problema que se abordó en .NET framework 3.5

    El código de error real de mapas para

    0x800703E3 "The I/O operation has been aborted because of either a thread exit or an application request."
    • El uso de .NET 4.0, y IIS 7.5
  4. 1

    intente configurar el tamaño máximo de archivo en el web config a uno más grande.

    Puede establecer el maxRequestLength (en kb)

    intentar no reclycle a los grupos de aplicaciones en iis a menudo también.

    • trate de no reciclar a los grupos de aplicaciones en IIS demasiado a menudo? ¿Qué quieres decir con eso?
    • He probado esto en IIS local en mi equipo, y no tenía la necesidad de la MaxRequestLength conjunto, y he descargado un archivo de 8 mb. Alguien sabe por qué funciona? No puedo subir más de 4mb sin que la entrada en la web.config.
    • por defecto casi todos los navegadores soporta sólo 2mb de tamaño (aprox) para subir, si intenta cargar sin la configuración que se va a obtener el error 500 o 404, tienes tu reemplazar este comportamiento por defecto con el maxRequestLength y en el servidor de producción cuando y aplicación de la piscina recicladas el proceso de trabajo que el host de la aplicación, deja que «tal vez» están matando a sus solicitudes en la aplicación, en Lugar de suspender abruptamente el proceso de trabajo, que pueden causar interrupciones en el servicio de intentar ro de reciclaje de los grupos de aplicaciones en la demanda.

Dejar respuesta

Please enter your comment!
Please enter your name here