【问题标题】:Calling async WCF method synchronously WITHOUT ServiceReference在没有 ServiceReference 的情况下同步调用异步 WCF 方法
【发布时间】:2018-03-11 16:25:27
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: c# wpf wcf asynchronous


    【解决方案1】:

    不幸的是,声明服务器 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 版本,而不是同步版本

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

    【讨论】:

      猜你喜欢
      • 2013-11-16
      • 2016-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-22
      • 2019-12-16
      相关资源
      最近更新 更多