委派同步WCF调用以启动异步进程

时间:2016-09-23 20:06:27

标签: c# .net wcf asynchronous

我需要修改WCF方法以异步运行。在我的情况下,[OperationContract(IsOneWay=true)]不是有效选项,因为客户端需要返回值。我无法控制客户端对现有WCF方法调用的消耗,我无法更改签名以返回void.我也无法修改客户端以强制进行异步WCF调用。客户端仍然需要调用其同步WCF调用并获得其硬编码响应。

在服务中,有适当的行为来管理监控和异常。我正在考虑的选项是让WCF服务自我注册或自我发现其端点,向服务添加单向WCF方法,并让同步方法调用WCF上的单向方法。我觉得这将是确保所有现有行为仍然适用的最安全的方法。这些行为不会收集或依赖来自最终客户端的任何信息。虽然在技术上可以从现有的同步调用中启动其他线程或异步调用,但我不喜欢它,因为我认为它可能会破坏状态信息,此时此信息与当前的WCF OperationContext相关联。

似乎我探索过的与此相关的所有选项都需要某种妥协,并且将同步呼叫转发到单向呼叫的选项将是最安全的。有没有更好的方法来解决这个问题,或者是否有可能强制WCF方法像OneWay调用那样立即返回客户端,但包含返回值?

1 个答案:

答案 0 :(得分:1)

有几种方法可以解决这个问题。您已经确定了其中一个(“链式WCF呼叫”)。另一方确实涉及TPL技术和技巧。

链式WCF呼叫。

使用这种方法,只需记住WCF交互中最昂贵的部分是有效载荷/参数的(反)序列化。就延迟而言,您的客户将支付该价格两次,因为您已将您的终端“链接”在一起。 “单向”呼叫配置仍然要求客户端“等待”,直到所有参数都正确反序列化并且呼叫“看起来很好”。这是因为单向调用仍然能够将SOAP异常提交回调用者,指示非法参数或崩溃的WCF行为等。只有“端点工作”(您编程的部分)的延迟才会被“保存”使用这种技术。

使用此方法,您还必须考虑必须使用与原始端点大多数或所有相同的行为配置单向例程。对于异常处理方面尤其如此。你说:

  
    

有一个有状态对象存储在OperationContext中,用于维护有关进程的信息。例如,如果存在异常,它将把所有相关的过程信息保存为包。

  

听起来你想从原始入口点剥离所有或大部分行为,而是让它们装饰你的内部单行程序。

TPL Finesse

Note: this next approach likely solves only half your problem...
because it does not address the WCF exception-handing scenario 
you called out.

通常,因为它是[ThreadStatic],所以关注不在线程和TPL例程之间流动的OperationContext是正确的。但是,根据MSDN,OperationContext.Current属性是公共的。使用闭包,您应该能够从WCF请求线程手动将OperationContext分配到新任务的新OperationContext.Current。

在这种情况下,您可以允许主WCF请求线程返回...但新任务可以使用相同的OperationContext引用运行。如果在新任务上抛出异常,它肯定不会由自定义WCF行为处理,因为主WCF请求线程可能已经很久以前已经退出并返回,因此它已经“通过”所有(异常处理)行为层。

简而言之,这就是你买的唯一东西是如果一个WCF行为将一个事务ID标记到OperationContext中,那么该事务ID将手动流入新的Task ...允许下游例程来获取它。

如果您要遵循这种方法,那么:

  • 尝试确保仍有回调等待后台任务...其目的是捕获任何异常,必要时记录并吞下。您不希望WCF应用程序中的独立任务具有未处理的异常。请记住,在这种情况下,您将无法获得WCF行为的帮助。
  • 确保任务具有相当有限的延迟......例如400到800毫秒。您不希望任务运行5分钟。据推测,您的WCF应用程序是IIS托管的,IIS可以在没有警告的情况下重新加载或卸载您的WCF AppDomain ...因为它不知道您创建了一个仍在工作的新任务。只要延迟受到限制,我怀疑你会遇到问题“IIS过早关闭你的WCF应用程序。”

最后,如果您的情况比这更复杂,请注意custom TaskScheduler instances