简体   繁体   English

在没有ServiceReference的情况下同步调用异步WCF方法

[英]Calling async WCF method synchronously WITHOUT ServiceReference

I have a self-hosted WCF service, .NET framework 4.5.2, using NetTcpBinding, and a WPF client (4.5.2 also) consuming this service remotely. 我有一个使用NetTcpBinding的自托管WCF服务,.NET Framework 4.5.2和一个远程使用此服务的WPF客户端(也为4.5.2)。 Thus far, all of my OperationContracts have been synchronous. 到目前为止,我所有的OperationContracts都是同步的。

I want to add an asynchronous OperationContract to the WCF service, but call it synchronously from the client (the reason for this is so I can use async/await inside the service method). 我想向WCF服务添加一个异步OperationContract,但是从客户端同步调用它(原因是这样,所以我可以在service方法中使用async / await)。

The catch: this solution doesn't use service references or SvcUtil. 问题是:此解决方案不使用服务引用或SvcUtil。 We're using the shared library pattern where the service contracts are defined in a shared library referenced by both the client and server. 我们使用共享库模式,其中服务合同在客户端和服务器都引用的共享库中定义。 Client proxies are created using ChannelFactory.CreateChannel. 使用ChannelFactory.CreateChannel创建客户端代理。

Is that even feasible? 那可行吗? I need to keep async/await out of the client but use it in the server method. 我需要保持异步/等待客户端,但在服务器方法中使用它。 If it's not possible, can I make the OperationContract synchronous but treat it like a Main method and use GetAwaiter().GetResult(), or will I run into deadlock issues? 如果不可能,是否可以使OperationContract同步但将其视为Main方法并使用GetAwaiter()。GetResult(),还是会遇到死锁问题?

Unfortunately the 3 separate ways of declaring your server's OperationContract create different interface signatures in your service contract assembly: 不幸的是,声明服务器的OperationContract的3种单独方法在服务合同程序集中创建了不同的接口签名:

  • Plain synchronous FooResponse Foo(FooRequest) 普通同步FooResponse Foo(FooRequest)
  • APM asynchronous IAsyncResult BeginFoo(FooRequest) / FooResponse EndFoo(IAsyncResult) APM异步IAsyncResult BeginFoo(FooRequest) / FooResponse EndFoo(IAsyncResult)
  • TAP asynchronous Task<FooResponse> FooAsync(FooRequest) TAP异步Task<FooResponse> FooAsync(FooRequest)

However, WCF treats these all the same "on the wire". 但是,WCF在“网上”将所有这些视为相同。 Add Service Reference is able to automagically convert the ServiceContract to a copy (in reference.cs) that supports the style needed for the client. “添加服务引用”能够自动将ServiceContract转换为支持客户端所需样式的副本(在reference.cs中)。

In your case, if you just switched your server to use TAP async, the client code would have to change to use .Wait() \\ .Result and maybe some .ConfigureAwait(false) depending on the app. 在您的情况下,如果只是将服务器切换为使用TAP异步,则客户端代码将不得不更改为使用.Wait() \\ .Result以及某些.ConfigureAwait(false)具体取决于应用程序。

With some hints from this answer there is an easier way: 此答案中得到一些提示, 是一种更简单的方法:

  • Retain the current synchronous service contract 保留当前的同步服务合同
  • Create a new async version of the whole service contract as <Name>Async but keep the same service contract attributes and operations 将整个服务合同的新异步版本创建为<Name>Async但保留相同的服务合同属性和操作
  • Switch all the operation methods to the FooAsync style above 将所有操作方法切换为上方的FooAsync样式
  • Specify ServiceContact.Name as the same as the old service contract if the Name was implicit 如果名称隐式,则将ServiceContact.Name指定为与旧服务合同相同
  • Change your server to implement the Async version of the service contract not the synchronous one 更改您的服务器以实现服务合同的Async版本,而不是同步的

Your client can then continue to use the original synchronous interface talking to the old or new server. 然后,您的客户端可以继续使用与新旧服务器通信的原始同步接口。

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

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