2009-12-11 15 views
20

Normalmente, uno escribe un código como este para descargar algunos datos usando una WebRequest.¿Cómo desechar correctamente una instancia de WebResponse?

using(WebResponse resp = request.GetResponse()) // WebRequest request... 
    using(Stream str = resp.GetResponseStream()) 
     ; // do something with the stream str 

Ahora bien, si se lanza un WebException, la WebException tiene una referencia al objeto WebResponse, que puede o no puede haber Desechar llamada (dependiendo del lugar donde ha ocurrido la excepción, o cómo se implementa la clase de respuesta) - No lo sé.

Mi pregunta es cómo se supone que uno debe lidiar con esto. Se supone que uno debe estar codificando muy a la defensiva, y deshacerse de la respuesta en el objeto WebException (eso sería un poco extraño, ya que WebException no es IDisposable). ¿O se supone que uno debe ignorar esto, acceder potencialmente a un objeto dispuesto o no disponer nunca de un objeto IDisposable? El ejemplo dado en la documentación de MSDN para WebException.Response es totalmente inadecuado.

+0

Sería útil si mencionó "WebException.Response" en el título de la pregunta. – Deantwo

Respuesta

2

Estoy bastante seguro de que cuando tiene un enunciado de uso el objeto está dispuesto, independientemente de cómo salga del bloque de uso (ya sea por excepción, regresar o simplemente progresar a través de la función).

Sospecho que descubrirá que el objeto dentro de WebException ya ha sido eliminado si lo deja salir del bloque de uso.

Recuerde, la eliminación de un objeto no necesariamente impide el acceso posterior. Puede ser impredecible tratar de llamar a métodos más tarde, causando excepciones de su propio comportamiento o muy extraño (y por lo tanto, no lo recomendaría). Pero incluso una gran parte del objeto aún se deja atrás para el recolector de basura, incluso si lo desecha y, por lo tanto, sigue estando accesible. El objetivo del desecho es, por lo general, limpiar los identificadores de recursos (como en este caso las conexiones TCP activas) que, por motivos de rendimiento, no se puede dejar de forma realista hasta que el recolector de elementos no utilizados los encuentre. Solo menciono esto para aclarar que no se excluye mutuamente para que se elimine y la excepción para mantener una referencia al mismo.

+0

De hecho. 'using' es azúcar sintáctico para try {} finally {}, y el objeto siempre estará dispuesto en el bloque finally. –

+1

¿Qué tal una excepción en GetResponse? El resultado no se habrá asignado a la variable resp, por lo tanto devuelto de la expresión, así dispuesto por la instrucción using. Entiendo que se puede acceder a un objeto eliminado, sin embargo, uno no debería hacerlo. Si esta es la intención de esta API, ¿no está diseñada la api "mal"? – Marcus

+0

No, si GetResponse arroja ningún objeto será eliminado. Pero no se puede saber si se ha creado un objeto, ya que solo las partes internas de GetResponse lo sabrán, por lo que es responsabilidad de GetResponse asegurarse de que no haya fugas en esta situación. – erikkallen

0

Una pregunta muy interesante (aunque vale la pena señalar que el objeto WebResponse será se eliminó al salir del uso). Mi intuición es que realmente no importa que tengas una referencia a este objeto WebResponse dispuesto siempre y cuando no intentes hacer nada "operativo" con él.

Usted puede probablemente todavía acceder a ciertas propiedades en la instancia para fines de registro (como el ResponseUri) sin obtener un ObjectDisposedException, pero la referencia general celebrada por la excepción no está ahí para que pueda seguir utilizando la instancia.

Me gustaría ver lo que dicen los demás.

4
using (var x = GetObject()) { 
    statements; 
} 

es (casi) equivalente a

var x = GetObject(); 
try { 
    statements; 
} 
finally { 
    ((IDisposable)x).Dispose(); 
} 

así será siempre dispuesta su objeto.

Esto significa que, en su caso

try { 
    using (WebResponse resp = request.GetResponse()) { 
     something; 
    } 
} 
catch (WebException ex) { 
    DoSomething(ex.Response); 
} 

ex.Response será el mismo objeto que el objeto resp local, que está dispuesto cuando llegue al controlador de captura. Esto significa que DoSomething está utilizando un objeto eliminado, y probablemente fallará con una ObjectDisposedException.

+0

Si la excepción se arroja en 'GetResponse', la instrucción' using' no se aplica aquí porque la excepción se lanza antes del bloque 'try' -' finally' -. No creo que la respuesta ya esté dispuesta en el bloque 'catch'. – ventiseis

15

he tenido un vistazo rápido con reflector, y ahora puedo decir:

  • WebResponse, siendo una clase abstracta, los delegados de todo su cierre/comportamiento disponer de sus clases derivadas.
  • HttpWebResponse, siendo la clase derivada que casi con seguridad usa aquí, en sus métodos de cierre/eliminación, solo se ocupa de eliminar la corriente de respuesta real. El resto del estado de la clase puede dejarse a merced tierna de la CG.

ello se deduce que es probable que sea seguro para hacer lo que quiera con respecto a la gestión de excepciones, siempre y cuando:

  • Cuando se lee la secuencia de respuesta de WebResponse en el bloque try, encerrarlo en una using bloque.
  • Si usted lee la secuencia de respuesta de WebException en el bloque catch, encierre en un bloque using también.
  • No hay necesidad de preocuparse por la eliminación de WebException sí mismo.
0

Obtengo casos similares en las conexiones EF DB.

Así que en realidad creo una lista de conexiones.

Al final del juego, bucle elimino todos.

2

HttpWebRequest hace internamente una memoria corriente de la corriente de red subyacente antes de tirar WebException, así que no hay recurso no administrado asociado con el WebResponse regresar de WebException.Response.

Esto hace innecesario llamar al Dispose() en él. De hecho, tratar de eliminar WebException.Response puede causar dolores de cabeza y problemas, ya que es probable que los usuarios de su código que intentan leer le asignen propiedades asociadas.

Sin embargo, es una buena práctica que debe desechar cualquier objeto IDisposable de su propiedad. Si decide hacerlo, asegúrese de no tener código, dependiendo de poder leer WebException.Response propiedades y/o su transmisión. La mejor manera sería manejar la excepción y lanzar un nuevo tipo de excepción para que no se filtre WebException hasta la persona que llama cuando sea posible.

Y también considere mudarse a HttpClient que reemplaza HttpWebRequest.

Descargo de responsabilidad: ninguna garantía implícita.

+0

La misma respuesta, pero mejor: https://stackoverflow.com/a/43131178/5815327 – Deantwo

Cuestiones relacionadas