2009-02-17 4 views
8

На веб-странице я звоню третьей стороне, которая не позволяет мне устанавливать таймаут программно. Я вызываю BeginInvoke и использую AsyncWaitHandle.WaitOne, чтобы подождать определенное количество времени.Нужно ли мне звонить EndInvoke после таймаута?

Если вызов истекает, я продолжаю и забываю о вызове потока, который я начал. Мой вопрос в том, должен ли я все-таки называть EndInvoke каким-то образом в ситуации тайм-аута? Замечание «ПРЕДОСТЕРЕЖЕНИЕ» на этой странице MSDN заставляет меня задаться вопросом, следует ли мне: http://msdn.microsoft.com/en-us/library/2e08f6yc(VS.71).aspx

Если вы считаете, что должен, то следующий вопрос: если моя веб-страница обработана и возвращается клиенту до того, как возвращается третья сторона , будет ли метод обратного вызова прослушивать код? Разве сервер не перестает искать активность после моего запроса/ответа?

Вот код, я использую:

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

ответ

0

Ну, я не мог игнорировать совет, который я видел повсюду, что, если я не обязательно позвоню EndInvoke, я МОГУте утечь некоторые ресурсы, поэтому мне пришлось попытаться спать по ночам и не волноваться приближался к скале.

Решение, которое я нашел, использует функцию обратного вызова async. Если вызов вернется вовремя, я вызываю EndInvoke. Если нет, я продолжаю щелчок на кнопке, и пусть функция обратного вызова async очищает беспорядок с помощью EndInvoke.

Чтобы ответить на мой вопрос о веб-приложении и «кто-нибудь будет слушать его после того, как я выйду и перейду», я обнаружил, что они будут - даже если я приурочусь и перейду, если я посмотрю позже вывода, этот асинхронный вызов вернется и запустит функцию обратного вызова, даже если я уже вернул вывод клиенту.

Я использовал некоторые из того, что я нашел на сайте: http://www.eggheadcafe.com/tutorials/aspnet/847c94bf-4b8d-4a66-9ae5-5b61f049019f/basics-make-any-method-c.aspx

... а также в сочетании с обратным вызовом вещами, которые я нашел в другом месте. Вот небольшая пробная функция того, что я сделал ниже. Он сочетает в себе часть того, что я нашел на Спасибо за вход каждого !:

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

Update:
Похоже, вы должны call EndInvoke always для вызова асинхронного (если его Control.BeginInvoke) или риска утечки ресурсов.

Это a discussion that is on the same lines. Предлагаемое решение - создать поток, который будет ждать завершения делегирования и вызвать EndInvoke. Однако в случае действительно Looong таймаута я думаю, что поток будет просто зависать.

Сво крайний случай, который, кажется, не будет документально подтверждено, что хорошо ... возможно сог таймауты не должно случиться .. исключительные случаи

2

Вполне возможно, что если вы не вызываете EndInvoke, вам 'утечка некоторого ресурса (выделена BeginInvoke).

Чтобы быть абсолютно безопасным, всегда вызывайте EndInvoke(), который будет блокироваться, так что сделайте это на каком-то фоновом потоке, который вам не нужен, или переключитесь на передачу обратного вызова, чтобы не сжигать поток во время ожидания).

На практике я не знаю, как часто это имеет значение (я думаю, что многие AsyncResults не будут течь, поэтому вам может повезти и быть в безопасности в этом случае).

Все это не имеет почти ничего общего с запроса-ответа и веб-серверов и этажерки, это просто как Начало/Конец программирования модель работает, независимо от того, какие приложения вы используете его.

+0

В отношении запроса-ответа: если я передать метод обратного вызова, но в то же время выполнить свою функцию ButtonClick и вернуться к клиенту, есть кто-нибудь прислушивается, когда этот поток BeginInvoke возвращается? В локальном приложении, если Main() завершено и закрыто, обратный вызов никогда не запускался. – Chad

0

Для общий случай шаблона async .NET, вызвав EndXXX, когда вы не хотите завершить операцию, запущенную с помощью ExXXX, будет ошибкой, потому что, если EndXXX вызывается до завершения операции, он должен блокироваться до тех пор, пока он не завершится. Это не очень помогает тайм-ауту.

Конкретный API может отличаться (например, WinForms явно не требует EndInvoke).

См. §9.2 «Руководства по разработке рамок» (2-е изд.). Или msdn.

Смежные вопросы