在网页上,我正在呼叫第三方,它不允许我以编程方式设置超时。我调用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;
}
}
答案 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。如果没有,我继续我的按钮单击,让异步回调函数清除乱七八糟的混乱。
要回答我自己关于网络应用程序的问题并且“在我超时并继续前进之后会有人在那里听”,我发现他们会 - 即使我超时并继续前进,如果我看到后来的输出,即使我已经将输出返回给客户端,异步调用将返回并运行回调函数。
找到的一些内容...以及与我在别处找到的回调内容相结合。这是我在下面做的一些示例函数。它结合了我在感谢所发现的一些内容!:
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.
}
}
}