繁体   English   中英

C#Fire和Forget在WebMethod中调用

[英]C# Fire and Forget call inside a WebMethod

我们有一个由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#方面。

您可以提供的任何帮助将非常感激。

您是否尝试在方法中使用“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);
    }
}

正如文档所说,应始终调用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。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM