超时后是否需要调用EndInvoke?

时间:2009-02-17 17:41:31

标签: timeout begininvoke

在网页上,我正在呼叫第三方,它不允许我以编程方式设置超时。我调用BeginInvoke并使用AsyncWaitHandle.WaitOne等待指定的时间。

如果通话超时,我继续前进,忘记我开始的话题。我的问题是,在超时情况下,我是否还要以某种方式调用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;
    }
}

4 个答案:

答案 0 :(得分:2)

如果你不调用EndInvoke,你可能会泄漏一些资源(由BeginInvoke分配)。

所以为了完全安全,总是调用EndInvoke()(它会阻塞,所以在你不需要的后台线程上执行,或者切换到传递回调以便在等待时不刻录线程)。

在实践中,我不知道它的重要性(我认为很多AsyncResults不会泄漏,因此在这种情况下你可能会很幸运并且安全。)

所有这些与请求 - 响应和Web服务器几乎没有任何关系,这就是开始/结束编程模型的工作原理,无论您使用它的是什么应用程序。

答案 1 :(得分:1)

<强>更新
好像你需要call EndInvoke always进行异步调用(除非它的Control.BeginInvoke)或冒险泄漏资源。

这是a discussion that is on the same lines。建议的解决方案是生成一个线程,该线程将等待委托实际完成并调用EndInvoke。然而,如果真的Looong超时,我认为该线程将挂起。

它的边缘情况似乎没有记录得那么好......也许不应该发生coz超时......例外情况

答案 2 :(得分:0)

对于.NET异步模式的一般情况,当您不想完成使用BeingXXX启动的操作时调用EndXXX将是一个错误,因为如果在操作完成之前调用EndXXX,它应该阻塞直到它完成。这对暂停来说没什么帮助。

特定的API可能不同(例如,WinForms显然不需要EndInvoke)。

见“框架设计指南”(第2版)§9.2。或msdn

答案 3 :(得分:0)

好吧,我不能忽视我到处看到的建议,如果我不确定调用EndInvoke,我可能会泄漏一些资源,所以我不得不尝试让它在晚上睡觉而不用担心我是接近悬崖。

我发现的解决方案使用了异步回调函数。如果呼叫及时返回,我在那里调用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.
        }       

    }
}