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

时间:2017-09-29 17:46:02

标签: c# wpf wcf asynchronous

我有一个自托管的WCF服务,.NET framework 4.5.2,使用NetTcpBinding,以及一个WPF客户端(4.5.2)也远程使用这个服务。到目前为止,我的所有OperationContracts都是同步的。

我想将一个异步OperationContract添加到WCF服务,但是从客户端同步调用它(原因是我可以在服务方法中使用async / await)。

catch:此解决方案不使用服务引用或SvcUtil。我们使用共享库模式,其中服务契约在客户端和服务器引用的共享库中定义。客户端代理是使用ChannelFactory.CreateChannel创建的。

这甚至可行吗?我需要保持async / await不在客户端,但在服务器方法中使用它。如果不可能,我可以将OperationContract同步,但将其视为Main方法并使用GetAwaiter()。GetResult(),还是会遇到死锁问题?

1 个答案:

答案 0 :(得分:0)

不幸的是,声明服务器OperationContract的3种不同方式在服务合同程序集中创建了不同的界面签名:

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

然而,WCF“在线上”对待这些都是相同的。 添加服务引用能够自动将ServiceContract转换为支持客户端所需样式的副本(在reference.cs中)。

在您的情况下,如果您只是将服务器切换为使用TAP异步,则客户端代码必须更改为使用.Wait() \ .Result,可能还需要一些.ConfigureAwait(false),具体取决于应用

通过this answer的一些提示,有一种更简单的方法:

  • 保留当前的同步服务合同
  • 创建整个服务合同的新异步版本为<Name>Async,但保留相同的服务合同属性和操作
  • 将所有操作方法切换为上面的FooAsync样式
  • 如果名称是隐式的,则指定ServiceContact.Name与旧服务合同相同
  • 更改服务器以实现服务合同的Async版本而不是同步版本

然后,您的客户端可以继续使用与旧服务器或新服务器通信的原始同步接口。