c# - 在控制台应用程序中等待异步操作后,WCF 客户端挂起任何操作

标签 c# wcf asynchronous async-await console-application

客户端示例代码:

var f = new DuplexChannelFactory<IService>(new Callback(), "NetTcpBinding_Name");
f.Credentials.ClientCertificate.Certificate = new X509Certificate2(certificateFile, "", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
f.Open();
IService s = f.CreateChannel();
Console.WriteLine("Lock status: " + s.IsUserLocked(id));
Task task = s.LockUserAsync(id);
Console.Write("Sent, awaiting ");
Console.WriteLine(task);
await task;
Console.WriteLine("Done");
Console.WriteLine("Lock status: " + s.IsUserLocked(id)); // never returns, timeout

等待异步方法 LockUserAsync 之后,任何同步方法都会永远挂起。调试器显示 IsUserLocked 实际上是第二次调用并返回。

它不会影响其他客户端:他们可以连接并从头开始重复同样的事情。

行为:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, 
  ConcurrencyMode = ConcurrencyMode.Multiple)]

契约(Contract):

[ServiceContract(CallbackContract = typeof(IServiceCallback))]
public interface IService
{
    [OperationContract]
    Task LockUserAsync(int userId);
    [OperationContract]
    int IsUserLocked(int id);
}

public interface IServiceCallback
{
    [OperationContract]
    void TestCallback(); // not used
}

这两种方法都只是占位符:

public async Task LockUserAsync(int id)
{
    return;
}

public int IsUserLocked(int id)
{
    return 0;
}

更新:它是一个控制台应用程序,因此没有同步上下文。如果我将 await 替换为 .Wait() 它会起作用。 ConfigureAwait(false) 没有任何改变。

我发现延续是以某种方式直接从 Task.SetResult 调用的。为什么不通过ThreadPool调用?

最佳答案

当没有像 ConsoleApplication 这样的 SynchronizationContext 时,TPL 会尝试通过直接从 Task.TrySetResult 调用延续来优化事情。由于我的代码从延续中调用 WCF,因此它会导致外部 WCF 代码内部出现死锁。

解决方案是在每个 await s.WcfMethod(); 之后放置 await Task.Yield();,这会导致从 ThreadPool 调用下一个延续

我个人认为这是 WCF 的一个错误:它应该在 Task.Run() 中调用 Task.SetResult 或传递 TaskCreationOptions.RunContinuationsAsynchronouslyTaskCompletionSource 设置。

关于c# - 在控制台应用程序中等待异步操作后,WCF 客户端挂起任何操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37087103/

相关文章:

c# - WPF - 如何与动态创建的控件实现双向数据绑定(bind)?

c# - C# 中的浅复制现实生活用法?

c# - 从控件中注销类处理程序 - WPF

java - 无法使用vertx创建文件

java - 在抛出异常之前在 Catch 子句中调用时,JPA 存储库不执行更新

c# - 在配置中找不到指定的命名连接,不打算与 EntityClient 提供程序一起使用,或者无效

wcf - WCF 的 RESTful 框架替代品

c# - WCF 服务问题仅在生产中返回较大的对象时

asp.net - WCF 错误 - 意外响应 : (400) Bad Request

Node.js + SQLite 异步事务