2009-02-17 14 views
8

En una página web, estoy llamando a un tercero que no me permite establecer el tiempo de espera programáticamente. Llamo a BeginInvoke y uso AsyncWaitHandle.WaitOne para esperar una cantidad específica de tiempo.¿Debo llamar a EndInvoke después de un tiempo de espera?

Si la llamada se agota, sigo adelante y me olvido de la llamada al hilo que comencé. Mi pregunta es, ¿todavía tengo que llamar a EndInvoke de alguna manera en una situación de tiempo de espera? El comentario "PRECAUCIÓN" en esta página de MSDN hace que me pregunte si debería: http://msdn.microsoft.com/en-us/library/2e08f6yc(VS.71).aspx

Si usted cree que debería, a continuación, la siguiente pregunta es si mi página Web por el procesamiento y vuelve al cliente antes de que el tercero vuelve , ¿el método de devolución de llamada estaría allí incluso escuchando ejecutar el código? ¿El servidor no deja de buscar actividad una vez que se realiza mi solicitud/respuesta?

Aquí está el código que estoy usando:

public class RemotePaymentProcessor 
{ 
    private delegate string SendProcessPaymentDelegate(string creditCardNumber); 

    private string SendProcessPayment(string creditCardNumber) 
    { 
     string response = string.Empty; 
     // call web service 
     SlowResponseService.SlowResponseService srs = new WebServiceTimeout.SlowResponseService.SlowResponseService(); 
     response = srs.GetSlowResponse(creditCardNumber); 
     return response; 
    } 

    public string ProcessPayment(string creditCardNumber, int timeoutMilliseconds) 
    { 
     string response = string.Empty; 

     SendProcessPaymentDelegate sppd = new SendProcessPaymentDelegate(SendProcessPayment); 
     IAsyncResult ar = sppd.BeginInvoke(creditCardNumber, null, new object()); 
     if (!ar.AsyncWaitHandle.WaitOne(timeoutMilliseconds, false)) 
     { 
      // Async call did not return before timeout 
      response = "TIMEOUT"; 
     } 
     else 
     { 
      // Async call has returned - get response 
      response = sppd.EndInvoke(ar); 
     } 
     return response; 
    } 
} 

Respuesta

0

Bueno, no podía pasar por alto el consejo vi todas partes que si no me aseguro de llamar EndInvoke, podría filtrarse algunos recursos, así que tuve que tratar de conseguir que dormir por la noche y no preocuparse I estaba acercándose a un acantilado.

La solución que encontré utilizó una función de devolución de llamada asíncrona. Si la llamada regresó a tiempo, invoco EndInvoke allí. Si no, continúo el clic de mi botón y dejo que la función de devolución de llamada asíncrona solucione el problema con EndInvoke.

Para responder a mi propia pregunta sobre una aplicación web y "¿Alguien estará allí para escuchar después de agotar el tiempo y seguir adelante?", Descubrí que, incluso si superaba el tiempo y continuaba, si miraba la última salida, esa llamada asincrónica devolverá y ejecutará la función de devolución de llamada, incluso si ya he devuelto la salida al cliente.

que utilizan algunos de lo que he encontrado en: http://www.eggheadcafe.com/tutorials/aspnet/847c94bf-4b8d-4a66-9ae5-5b61f049019f/basics-make-any-method-c.aspx

... así como la combinación con el material de devolución de llamada que encontré en otro lugar. Aquí hay una pequeña función de muestra de lo que hice a continuación. Combina algo de lo que he encontrado en Gracias por el aporte de todos !:

public class RemotePaymentProcessor 
{  
    string currentResponse = string.Empty; 

    private delegate string SendProcessPaymentDelegate(string creditCardNumber);  
    private string SendProcessPayment(string creditCardNumber)  
    {   
     SlowResponseService.SlowResponseService srs = new WebServiceTimeout.SlowResponseService.SlowResponseService();   
     string response = srs.GetSlowResponse(creditCardNumber);   
     return response;  
    }  

    public string ProcessPayment(string creditCardNumber, int timeoutMilliseconds)  
    {   
     string response = string.Empty;   
     SendProcessPaymentDelegate sppd = new SendProcessPaymentDelegate(SendProcessPayment);   
     IAsyncResult ar = sppd.BeginInvoke(creditCardNumber, new AsyncCallback(TransactionReturned), sppd);   
     if (!ar.AsyncWaitHandle.WaitOne(timeoutMilliseconds, false))   
     {    
      // Async call did not return before timeout    
      response = "TIMEOUT";   
     }   
     else    
     {    
      // Async call has returned - get response    
      response = sppd.EndInvoke(ar);   
     }   

     currentResponse = response; // Set class variable 
     return response;  
    } 

    private void TransactionReturned(IAsyncResult ar) 
    { 
     string response = string.Empty; 

     // Get delegate back out of Async object 
     SendProcessPaymentDelegate sppd = (SendProcessPaymentDelegate)ar.AsyncState; 

     // Check outer class response status to see if call has already timed out 
     if(currentResponse.ToUpper().Equals("TIMEOUT")) 
     { 
      // EndInvoke has not yet been called so call it here, but do nothing with result 
      response = sppd.EndInvoke(ar); 
     } 
     else 
     { 
      // Transaction must have returned on time and EndInvoke has already been called. Do nothing. 
     }  

    } 
} 
1

Actualización:
parece que necesita para call EndInvoke always para una llamada asíncrona (a menos que su Control.BeginInvoke) o de riesgo los recursos con fugas.

Aquí está a discussion that is on the same lines. La solución sugerida es generar un hilo que espere a que el delegado complete realmente y llame a EndInvoke. Sin embargo, en caso de un tiempo de espera realmente largo, creo que el hilo simplemente se cuelga.

Su borde un caso que no parece estar documentado que bueno ... tal vez coz no se supone que los tiempos de espera suceda .. casos excepcionales

2

Es posible que si no se llama a EndInvoke, se Perderá algún recurso (asignado por BeginInvoke).

Para estar totalmente seguro, siempre llame a EndInvoke() (que se bloqueará, hágalo en algún hilo de fondo que no necesite, o cambie a pasar una devolución de llamada para no grabar un hilo mientras espera).

En la práctica, no sé con qué frecuencia importa (creo que muchos AsyncResults no tendrán fugas, por lo que puede tener suerte y estar seguro en este caso).

Todo esto tiene casi nada que ver con los servidores de petición-respuesta y de la tela y otras cosas, esto es sólo la forma en la Begin/End funciona el modelo de programación, independientemente de la aplicación que se esté usando,.

+0

En cuanto a la petición-respuesta: si paso un método de devolución de llamada, pero en la media hora de completar mi función ButtonClick y volver a cliente, ¿hay ¿Alguien escucha cuando regresa ese hilo de BeginInvoke? En una aplicación local, si Main() finalizó y cerró la aplicación, la devolución de llamada nunca se activó. – Chad

0

Para el caso general del patrón asíncrono .NET, llamar a EndXXX cuando no se quiere completar la operación iniciada con BeingXXX será un error porque si se llama a EndXXX antes de que la operación se complete, debe bloquearse hasta que se complete. Lo cual no es de mucha ayuda para un tiempo de espera.

Una API específica puede ser diferente (por ejemplo, WinForms explícitamente no requiere EndInvoke).

Ver §9.2 de "Pautas de diseño del marco" (2da ed). O msdn.

Cuestiones relacionadas