我们有一个由Delphi CGI同步调用的C#WebMethod(不要问!)。这种方法很好,除非我们切换到运行速度慢得多的灾难恢复环境。问题是Delphi WinInet Web请求的超时时间为30秒,由于Microsoft承认的错误而无法更改。在灾难恢复环境中,C#WebMethod可能需要30秒以上的时间,并且Delphi CGI可能会失效。
我们现在编写了C#WebMethod来识别它所处的环境,如果它处于灾难恢复模式,那么我们在一个线程中调用后续方法并立即响应CGI,以便它在30秒内。这在理论上是有道理的,但我们发现这些线程调用是不稳定的,并且不会100%执行。我们获得了大约70%的成功率。
这显然是不可接受的,我们必须达到100%。使用Delegate.BeginInvoke()调用线程,我们已经在其他上下文中成功使用了它们,但是由于某种原因他们不喜欢这个...显然没有EndInvoke(),因为我们需要立即响应CGI,这是WebMethod的终结。
以下是WebMethod的简化版本:
[WebMethod]
public string NewBusiness(string myParam)
{
if (InDisasterMode())
{
// Thread the standard method call
MethodDelegate myMethodDelegate = new MethodDelegate(ProcessNewBusiness);
myMethodDelegate.BeginInvoke(myParam, null, null);
// Return 'ok' to caller immediately
return 'ok';
}
else
{
// Call standard method synchronously to get result
return ProcessNewBusiness(myParam);
}
}
如果在WebService WebMethod环境中使用,这种“即发即忘”调用是否会失败?如果有,那么还有其他选择吗?
不幸的是,改变Delphi方面对我们来说不是一个选择 - 解决方案必须在C#方面。
非常感谢您提供的任何帮助。
答案 0 :(得分:10)
您是否尝试在方法中使用“HttpContext”?如果是这样,你应该首先将它存储在局部变量中......另外,我只使用ThreadPool.QueueUserWorkItem 。
示例:
[WebMethod]
public string NewBusiness(string myParam)
{
if (InDisasterMode())
{
// Only if you actually need this...
HttpContext context = HttpContext.Current;
// Thread the standard method call
ThreadPool.QueueUserWorkItem(delegate
{
HttpContext.Current = context;
ProcessNewBusiness(myParam);
});
return 'ok';
}
else
{
// Call standard method synchronously to get result
return ProcessNewBusiness(myParam);
}
}
答案 1 :(得分:0)
正如文档所说,应始终调用EndInvoke,因此您必须创建一个帮助程序来执行FireAndForget操作,如下所示: http://www.reflectionit.nl/Blog/default.aspx?guid=ec2011f9-7e8a-4d7d-8507-84837480092f
我粘贴代码:
public class AsyncHelper {
delegate void DynamicInvokeShimProc(Delegate d, object[] args);
static DynamicInvokeShimProc dynamicInvokeShim = new
DynamicInvokeShimProc(DynamicInvokeShim);
static AsyncCallback dynamicInvokeDone = new
AsyncCallback(DynamicInvokeDone);
public static void FireAndForget(Delegate d, params object[] args) {
dynamicInvokeShim.BeginInvoke(d, args, dynamicInvokeDone, null);
}
static void DynamicInvokeShim(Delegate d, object[] args) {
DynamicInvoke(args);
}
static void DynamicInvokeDone(IAsyncResult ar) {
dynamicInvokeShim.EndInvoke(ar);
}
}
我们在我们的应用程序中成功使用此代码,尽管它不是Web。