委派一个同步WCF调用来启动一个异步进程

本文关键字:一个 启动 异步 进程 同步 委派 WCF 调用 | 更新日期: 2023-09-27 18:08:45

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

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

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

委派一个同步WCF调用来启动一个异步进程

有几种方法可以做到这一点。您已经确定了其中的一个("链式WCF调用")。另一个确实涉及TPL技术和技巧。

链式WCF调用。

使用这种方法,请记住WCF交互中最昂贵的部分是有效负载/参数的(反)序列化。在延迟方面,您的客户端将付出两次代价,因为您已经"链接"了。你的端点在一起。"oneway"呼叫配置仍然要求客户端"等待"。直到所有参数都被正确反序列化,并且调用"看起来不错"。这是因为单向调用仍然有能力向调用者抛出SOAP异常,指示非法参数或崩溃的WCF行为等。只有"端点"的延迟才有效。(您编写的部分)将被"保存"。

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

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

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

TPL技巧

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

在一般情况下,因为它是[ThreadStatic],你是正确的关注OperationContext不在线程和TPL例程之间流动。然而,根据MSDN, OperationContext。目前的财产是公有的。使用闭包,您应该能够手动将来自WCF请求线程的OperationContext分配给新的OperationContext。新任务的电流。

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

简而言之,如果WCF行为将事务ID戳入OperationContext中,那么该事务ID将手动流到新Task中,这将为您提供唯一的东西。允许下游例程拾取它

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

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

最后,如果您的情况比这更复杂,请注意自定义TaskScheduler实例