2010-09-21 10 views
6

Todo, estoy intentando cancelar dos HttpWebRequests simultáneas utilizando un método similar al código siguiente (mostrado en pseudo-ish C#).Asesinato del objeto HttpWebRequest utilizando Thread.Abort

El método Principal crea dos hilos que crean HttpWebRequests. Si el usuario lo desea, puede cancelar las solicitudes haciendo clic en un botón que luego llama al método Abortar.

private Thread first; 
private Thread second; 
private string uri = "http://somewhere"; 

public void Main() 
{ 
    first = new Thread(GetFirst); 
    first.Start(); 

    second = new Thread(GetSecond); 
    second.Start(); 

    // Some block on threads... like the Countdown class 
    countdown.Wait(); 
} 

public void Abort() 
{ 
    try 
    { 
    first.Abort(); 
    } 
    catch { // do nothing } 

    try 
    { 
    second.Abort(); 
    } 
    catch { // do nothing } 
} 

private void GetFirst(object state) 
{ 
    MyHandler h = new MyHandler(uri); 
    h.RunRequest(); 
} 

private void GetSecond(object state) 
{ 
    MyHandler h = new MyHandler(uri); 
    h.RunRequest(); 
} 

El primer hilo se interrumpe por un SocketException:

A blocking operation was interrupted by a call to WSACancelBlockingCall 

El segundo hilo se cuelga en GetResponse().

¿Cómo puedo cancelar ambas solicitudes de forma que el servidor web sepa que la conexión se ha cancelado?, y/o, ¿Hay una mejor manera de hacer esto?

ACTUALIZACIÓN

Como se ha sugerido, una buena alternativa sería utilizar BeginGetResponse. Sin embargo, no tengo acceso al objeto HttpWebRequest; se abstrae en la clase MyHandler. He modificado la pregunta para mostrar esto.

public class MyHandler 
{ 
    public void RunRequest(string uri) 
    { 
    HttpWebRequest req = HttpWebRequest.Create(uri); 
    HttpWebResponse res = req.GetResponse(); 
    } 
} 
+0

Desafortunadamente, todo lo que puedo ofrecer como respuesta es modificar MyHandler si tiene acceso. De lo contrario, la única forma de matarlo es cómo lo está haciendo actualmente. Alternativamente, puede proporcionar un tiempo de espera utilizando la opción HttpWebRequest.Timeout: http: //msdn.microsoft.com/en-us/library/system.net.httpwebrequest.timeout.aspx –

Respuesta

4

Uso BeginGetResponse para iniciar la llamada y luego usar el método Abort en la clase para cancelarla.

http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest_methods.aspx

Creo Abort no funcionará con el sincrónica GetResponse:

http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.abort.aspx

Si usted tiene que pegarse con la versión sincrónica, para matar a la situación, lo único que puede hacer es abortar la amenaza. A renunciar a la espera, puede especificar un tiempo de espera:

http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.timeout.aspx

Si tiene que matar el proceso, yo diría que el lanzamiento dentro de un nuevo dominio de aplicación y dejando caer el dominio de aplicación cuando se quiere matar a la solicitud; en lugar de abortar un hilo dentro de su proceso principal.

+1

Adam: ¿Podría explicar su comentario? ¿Crees que Abort no funcionará con el GetResponse sincrónico? ¿Dónde encuentras eso? – Armbrat

+0

No se mencionó explícitamente, pero la oración: "El método Abort ejecutará sincrónicamente la devolución de llamada especificada a los métodos BeginGetRequestStream o BeginGetResponse si se llama al método Abort mientras cualquiera de estas operaciones está pendiente". me llevó a dar a entender que solo era válido en esos métodos. Además, a menos que realice una llamada entre hilos en su objeto HttpWebRequest, no podrá llamar a Abort porque actualmente se bloqueará en GetResponse. –

3

Una ThreadAbortException es altamente inespecífica. HttpWebRequest ya admite una forma de cancelar la solicitud de forma predecible con el método Abort(). Te recomiendo que lo uses en su lugar.

Tenga en cuenta que seguirá recibiendo una WebException en el hilo, diseñada para informarle que la solicitud se canceló externamente. Prepárate para atraparlo.

2

Esto podría deberse a la agrupación de conexiones de .NET. Cada instancia de WebRequest tiene un ServicePoint que describe el destino con el que desea comunicarse (dirección del servidor, puerto, protocolo, ...). Estos ServicePoints se reutilizarán, por lo que si crea 2 WebRequests con la misma dirección de servidor, puerto y protocolo, compartirán la misma instancia de ServicePoint.

Cuando llama a WebRequest.GetResponse() utiliza el conjunto de conexiones proporcionado por el ServicePoint para crear conexiones.Si luego mata el hilo con Thread.Abort() NO devolverá la conexión al grupo de conexiones de ServicePoint, por lo que el ServicePoint cree que esta conexión todavía está en uso. Si se alcanza el límite de conexión de ServicePoint (predeterminado: 2) no creará ninguna conexión nueva, sino que esperará a que se devuelva una de las conexiones abiertas.

Puede aumentar el límite de conexión de esta manera:

HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url); 
httpRequest.ServicePoint.ConnectionLimit = 10; 

o puede utilizar el límite de conexiones por defecto, por lo que cada nueva ServicePoint utilizará este límite:

System.Net.ServicePointManager.DefaultConnectionLimit = 10; 

También puede utilizar ServicePoint .CurrentConnections para obtener el número de conexiones abiertas.

se puede utilizar el siguiente método para abortar el hilo:

private Thread thread; 
    private Uri uri; 

    void StartThread() 
    { 
     thread = new Thread(new ThreadStart(() => 
     { 
      WebRequest request = WebRequest.Create(uri); 
      request.ConnectionGroupName = "SomeConnectionGroup"; 

      var response = request.GetResponse(); 

      //... 
     })); 
     thread.Start(); 
    } 

    void AbortThread() 
    { 
     thread.Abort(); 
     ServicePointManager.FindServicePoint(uri).CloseConnectionGroup("SomeConnectionGroup"); 
    } 

Recuerde que todas las conexiones al mismo servidor (o ServicePoint) que tienen el mismo nombre de grupo de conexión serán asesinados. Si tiene varios subprocesos simultáneos, es posible que desee asignarles nombres de grupos de conexión únicos.

Cuestiones relacionadas