2009-02-17 15 views
8

In una pagina Web, sto chiamando una terza parte che non mi consente di impostare il timeout in modo programmatico. Chiamo BeginInvoke e uso AsyncWaitHandle.WaitOne per aspettare un intervallo di tempo specificato.Devo chiamare EndInvoke dopo un timeout?

Se la chiamata scade, vado avanti e mi dimentico della chiamata al thread che ho iniziato. La mia domanda è, devo ancora chiamare EndInvoke in qualche modo in una situazione di timeout? L'osservazione "ATTENZIONE" su questa pagina MSDN mi chiede se dovrei: http://msdn.microsoft.com/en-us/library/2e08f6yc(VS.71).aspx

Se credi che dovrei, la prossima domanda è se la mia pagina web viene elaborata e ritorna al client prima che la terza parte ritorni , il metodo di callback sarebbe anche lì in ascolto per eseguire il codice? Il server non smette di cercare attività una volta che la mia richiesta/risposta è stata eseguita?

Ecco il codice che sto utilizzando:

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

risposta

0

Beh, non potevo ignorare il consiglio che ho visto ovunque che se non mi fossi assicurato di chiamare EndInvoke, potrei perdere alcune risorse, quindi ho dovuto cercare di farlo entrare per dormire la notte e non preoccuparmi si stava avvicinando a una scogliera.

La soluzione che ho trovato utilizzava una funzione di richiamata asincrona. Se la chiamata è tornata in tempo, chiamo EndInvoke lì. In caso contrario, continuo il tasto clic e la funzione di richiamata asincrona ripulisce il problema con EndInvoke.

Per rispondere alla mia domanda su un'app Web e "ci sarà qualcuno ad ascoltare dopo che avrò finito e andare avanti", ho scoperto che lo faranno - anche se sono scaduto e sono andato avanti, se ho guardato il dopo in uscita, quella chiamata asincrona restituirà ed eseguirà la funzione di richiamata, anche se ho già restituito l'output al client.

ho usato un po 'di quello che ho trovato su: http://www.eggheadcafe.com/tutorials/aspnet/847c94bf-4b8d-4a66-9ae5-5b61f049019f/basics-make-any-method-c.aspx

... così come la combinazione con la roba richiamata ho trovato altrove. Ecco una piccola funzione di esempio di ciò che ho fatto qui sotto. Esso combina alcune delle cose che ho trovato su Grazie per l'input di tutti !:

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

Aggiornamento:
Sembra come è necessario call EndInvoke always per una chiamata asincrona (a meno che la sua Control.BeginInvoke) o di rischio risorse perdite.

Ecco il numero a discussion that is on the same lines. La soluzione suggerita è di generare un thread che attenderà il completamento effettivo del delegato e chiamare EndInvoke. Tuttavia, in caso di un timeout davvero Looong, penso che il thread si bloccherebbe.

Il suo un caso limite che non sembra essere documentato che bene ... forse coz timeout non dovrebbero accadere .. casi eccezionali

2

E 'possibile che se non chiami EndInvoke, è Perderai qualche risorsa (allocata da BeginInvoke).

Quindi, per essere totalmente sicuro, chiama sempre EndInvoke() (che bloccherà, quindi fallo su qualche thread in background che non ti serve, o passa a passare una richiamata in modo da non masterizzare un thread mentre aspetti).

In pratica non so quanto conta (credo che molti AsyncResults non colmino, quindi potresti essere fortunato ed essere sicuro in questo caso).

Tutto questo non ha quasi nulla a che fare con i server di richiesta-risposta e web e quant'altro, questo è solo come il Begin/End modello di programmazione funziona, indipendentemente da quale applicazione che si sta utilizzando in.

+0

Per quanto riguarda la richiesta-risposta: se mi passa un metodo di callback, ma nel frattempo completare la mia funzione ButtonClick e tornare al cliente, è lì qualcuno che ascolta quando restituisce quel thread BeginInvoke? In un'app locale, se Main() ha terminato e chiuso l'app, la funzione di callback non è mai stata attivata. – Chad

0

Per il caso generale del pattern async .NET, chiamare EndXXX quando non si desidera completare l'operazione avviata con BeingXXX sarà un errore, perché se EndXXX viene chiamato prima che l'operazione abbia completato, dovrebbe bloccarsi fino al suo completamento. Che non è di grande aiuto per un timeout.

Un'API specifica potrebbe essere diversa (ad esempio, WinForms non richiede esplicitamente EndInvoke).

Vedere §9.2 di "Linee guida per la progettazione di quadri" (2a ed). O msdn.

Problemi correlati