简体   繁体   English

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

[英]Delegating a synchronous WCF call to start an asynchronous process

I need to modify a WCF method to run asynchronously. 我需要修改WCF方法以异步运行。 [OperationContract(IsOneWay=true)] is not a valid option in my case as the client expects a return value. 在我的情况下, [OperationContract(IsOneWay=true)]不是有效的选项,因为客户期望返回值。 I do not have control over the client's consumption of the existing WCF method call and I cannot change the signature to return void. 我无法控制客户端对现有WCF方法调用的使用,也无法更改签名以返回void. I also cannot modify the client to force an asynchronous WCF call. 我也无法修改客户端以强制执行异步WCF调用。 The client will still have to expect to call its synchronous WCF call and get its hard-coded response. 客户端仍然必须期望调用其同步WCF调用并获得其硬编码响应。

Within the service, there are behaviors in place to manage monitoring and exceptions. 在服务内,存在用于管理监视和异常的行为。 The option that I was considering would be to have the WCF service self-register or self-discover its endpoint, add a One-Way WCF method to the service, and have the synchronous method call the One-Way method over WCF. 我正在考虑的选项是让WCF服务自动注册或自我发现其端点,向该服务添加单向WCF方法,并使同步方法在WCF上调用单向方法。 I felt that would be the safest way to ensure that all of the existing behaviors still applied. 我认为这是确保所有现有行为仍然适用的最安全的方法。 The behaviors don't collect or depend on any information from the end client. 这些行为不会收集或依赖最终客户端的任何信息。 While it seems technically possible to start other threads or asynchronous calls from within the existing synchronous call, I don't like that as I believe it could corrupt state information that, at this point, is tied to the current WCF OperationContext. 尽管从现有的同步调用中启动其他线程或异步调用在技术上似乎是可行的,但我不喜欢这样做,因为我认为这可能会破坏与当前WCF OperationContext绑定的状态信息。

It seems that all options that I've explored related to this require some sort of compromise and that the option of having the synchronous call forwarded over to the One-Way call would be the safest. 看来,我探索过的与此相关的所有选项都需要某种折衷,并且将同步呼叫转移到单向呼叫的选项是最安全的。 Is there a better way to go about this or is it possible to force a WCF method to give the same immediate return to a client as a OneWay call, but include a return value? 有没有更好的方法可以解决此问题,还是可以强制WCF方法将与OneWay调用相同的立即返回给客户端,但包括返回值?

There's a couple ways to go about this. 有两种方法可以解决此问题。 You've already identified one of them ("Chained WCF Calls"). 您已经确定了其中一个(“链式WCF调用”)。 The other does indeed involve TPL techniques, and finesse. 另一个确实涉及TPL技术和技巧。

Chained WCF Calls. 链接的WCF呼叫。

With this approach, just remember the most expensive part of WCF interactions is the (de-)serialization of payload / parameters. 使用这种方法时,请记住WCF交互最昂贵的部分是有效载荷/参数的(反序列化)。 In terms of latency, your client will pay that price twice because you've "chained" your endpoints together. 在延迟方面,您的客户端将支付两次价格,因为您已将端点“链接”在一起。 The "oneway" call configuration still requires that the client "wait" until all parameters have deserialized correctly and the call "looks good." “单向”调用配置仍然要求客户端“等待”,直到所有参数正确反序列化为止,并且调用“看起来不错”。 This is because oneway calls still have the ability to raise a SOAP exception back to the caller indicating illegal parameters, or crashed WCF behaviors, etc. Only the latency of the "endpoint work" (the part you program) will be "saved" by using this technique. 这是因为单向调用仍具有向调用者发出SOAP异常的能力,指示非法参数或崩溃的WCF行为等。只有“端点工作”(您编程的部分)的延迟才会被“保存”,使用这种技术。

With this approach, you must also consider that your oneway routine must be configured with most or all the same behaviors as your original endpoint. 使用这种方法,您还必须考虑您的单向例程必须配置为具有与原始端点大多数或所有相同的行为。 This is particularly true for the exception handling aspect. 对于异常处理方面尤其如此。 You said: 你说:

There is a stateful object that is stored in the OperationContext that maintains information about the process. 在OperationContext中存储了一个有状态对象,该对象维护有关流程的信息。 If, for instance, there is an exception, it will save all of the relevant process information as a package. 例如,如果存在异常,它将把所有相关过程信息保存为一个包。

It sounds like you would want to strip all or most of the behaviors from the original entry point, and instead have them decorate your internal oneway routine. 听起来您想从原始入口点剥离所有或大多数行为,而是让它们装饰您的内部单向例程。

TPL Finesse 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.

In general, because it is [ThreadStatic] you are correct to be concerned about OperationContext not flowing between threads and TPL routines. 通常,因为它是[ThreadStatic],所以您要担心OperationContext在线程和TPL例程之间不流动是正确的。 However, according to MSDN, the OperationContext.Current property is public. 但是,根据MSDN,OperationContext.Current属性是公共的。 Using closures, you should be able manually assign the OperationContext from the WCF request thread onto a new OperationContext.Current of a new Task. 使用闭包,您应该能够将WCF请求线程中的OperationContext手动分配给新Task的新OperationContext.Current。

In this case, you could allow the primary WCF request thread to return...and yet the new Task could run with the same OperationContext reference. 在这种情况下,您可以允许主WCF请求线程返回...而新的Task可以使用相同的OperationContext引用运行。 If an exception is thrown on the new Task, it certainly will not be handled by a custom WCF behavior, since the primary WCF request thread would presumably have already exited-and-returned long ago, and thus it already "passed through" all the (exception handling) behavior layers. 如果在新Task上抛出异常,则肯定不会通过自定义WCF行为对其进行处理,因为主要WCF请求线程可能早就已经退出并返回了,因此它已经“遍历”了所有(异常处理)行为层。

In short, the only thing this buys you is if a WCF behavior had stamped a transaction ID into the OperationContext, then that transaction ID would manually flow onto the new Task...allowing a down-stream routine to pick it up. 简而言之,这给您带来的唯一好处是,如果WCF行为已将交易ID标记到OperationContext中,则该交易ID将手动流到新Task上……从而允许下游例程将其提取。

If you were to follow this approach then: 如果您要遵循这种方法,则:

  • Try to ensure there is still a callback waiting for the background Task...its purpose is to catch any exception, log it if necessary, and swallow. 尝试确保仍有一个回调在等待后台Task ...它的目的是捕获任何异常,如有必要,请记录并吞下。 You don't want independent Task in your WCF app having exceptions that are unhandled. 您不希望WCF应用程序中的独立Task具有未处理的异常。 Remember, you will have no help from WCF behaviors in this case. 请记住,在这种情况下,您不会从WCF行为获得帮助。
  • Be sure that the Task has a fairly confined latency...such as 400 to 800ms. 确保任务具有相当有限的延迟...例如400到800ms。 You don't want a Task to run for 5 minutes. 您不希望任务运行5分钟。 Presumably your WCF app is IIS hosted, and IIS can reload or unload your WCF AppDomain without warning...because it has no idea that you've created a new Task that is still doing work. 大概您的WCF应用程序是由IIS托管的,并且IIS可以在没有警告的情况下重新加载或卸载WCF AppDomain ...因为它不知道您已经创建了仍在工作的新Task。 As long as the latency is constrained, I doubt you will run into issues with IIS shutting down your WCF app "too soon." 只要延迟受到限制,我怀疑IIS会“过早”关闭WCF应用程序时会遇到问题。

Finally, if your situation is more complex than this, be aware of custom TaskScheduler instances . 最后,如果您的情况比这更复杂,请注意自定义TaskScheduler实例

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

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