gpt4 book ai didi

c# - 从不同线程调用时,WCF Duplex 回调方法从不执行

转载 作者:太空狗 更新时间:2023-10-30 01:33:30 25 4
gpt4 key购买 nike

好吧,我对这件事束手无策。我有一个 WCF 双工服务。以下是架构的工作原理:

  1. 客户端打开到端点的连接并提供回调实现
  2. 该服务接受该请求并在其他线程上做一些事情(可能是 1 秒也可能是 2 分钟,这就是我不使用异步操作的原因)
  3. 处理完成后调用客户端的回调

问题是当服务调用那个回调时,似乎没有任何反应。没有错误,什么都没有。经过进一步调查,我在服务器跟踪中发现了一个异常:

The I/O operation has been aborted because of either a thread exit or an application request

这发生在尝试执行回调之后。

客户端永远不会收到响应或关闭。所发生的一切是,由于初始请求是在与主线程不同的线程上发出的,它只会永远等待该线程完成。

最奇怪的是,如果我尝试在客户端调用的操作中调用回调,而不进入另一个线程,一切正常 - 回调被成功调用,这让我相信我已经配置服务正确,但存在线程/死锁问题。

以下是我调用该服务的方式:

SubmissionServiceClient client = CreateClientInstance();
client.Open();
Guid executionId = await client.SubmitAsync(submission);
submissionCompletionSource.Task.Wait(); //waits for the callback to be called (I omitted the extra wiring code for better readability)
client.Close();

private SubmissionServiceClient CreateClientInstance()
{
NetHttpBinding binding = new NetHttpBinding();
binding.WebSocketSettings.TransportUsage = WebSocketTransportUsage.Always;
EndpointAddress endpointAddress = new EndpointAddress("ws://localhost:9080/SubmissionRouter");
InstanceContext instanceContext = new InstanceContext(this);
SubmissionServiceClient submissionServiceClient = new SubmissionServiceClient(instanceContext,binding,endpointAddress);
return submissionServiceClient;
}

这是回调操作:

public void SubmissionProcessed(SubmissionResultDto result)
{
submissionCompletionSource.TrySetResult(result);
}

这是客户端调用的服务操作:

public Guid Submit(SubmissionDto submission, ISubmissionCallback callback)
{
ExecutionDto execution = new ExecutionDto()
{
Id = Guid.NewGuid(),
Submission = submission
};
RequestExecution(execution); //Queues the execution of the operation
submissions.Add(execution.Id, callback);

return execution.Id;
}

这是服务调用客户端回调的地方(此方法在与发出初始请求的线程不同的线程上执行):

                ISubmissionCallback callback = submissions[submissionResult.ExecutionId];
callback.SubmissionProcessed(submissionResult);

服务行为:

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

正如您在提交时看到的那样,该服务将回调存储在字典中,并与一个 id 配对,稍后它会使用它来检索回调并调用它。我相信它失败的原因是因为我试图在不同的线程上执行此操作。

编辑:我向服务添加了一个 Ping 操作,它调用另一个线程,该线程挂起 3 秒,然后在客户端上调用一个 Pong 函数。

public void Ping()
{
var callback = OperationContext.Current.GetCallbackChannel<ISubmissionCallback>();
Task.Run(() =>
{
System.Threading.Thread.Sleep(3000);
callback.Pong();
});
}

客户: 类(class)计划 { 静态无效主要(字符串[]参数) { NetHttpBinding 绑定(bind) = new NetHttpBinding(); binding.WebSocketSettings.TransportUsage = WebSocketTransportUsage.Always; EndpointAddress endpointAddress = new EndpointAddress("ws://localhost:9080/SubmissionRouter"); InstanceContext instanceContext = new InstanceContext(new Callback()); SubmissionServiceClient submissionServiceClient = new SubmissionServiceClient(instanceContext, binding, endpointAddress);

        submissionServiceClient.Ping();

Console.Read();
}

public void SubmissionProcessed(SubmissionResultDto result)
{
throw new NotImplementedException();
}
class Callback : ISubmissionServiceCallback
{
public void Pong()
{
Console.WriteLine("Pong!");
}

public void SubmissionProcessed(SubmissionResultDto result)
{

}
}
}

这确实成功了。我设法在客户端收到了我的答复。我现在正式完全迷路了。

最佳答案

如果您使用 submissionCompletionSource.Task.Wait(); 阻塞 UI 线程,这将导致您的死锁。默认情况下,WCF 回调发生在 UI 线程上,您可以使用 CallbackBehaviorAttribute

更改行为
[CallbackBehaviorAttribute(UseSynchronizationContext=false)]
class Callback : ISubmissionServiceCallback
{
public void Pong()
{
Console.WriteLine("Pong!");
}

public void SubmissionProcessed(SubmissionResultDto result)
{

}
}

或者不阻塞 UI 线程。

SubmissionServiceClient client = CreateClientInstance();
client.Open();
Guid executionId = await client.SubmitAsync(submission);
await submissionCompletionSource.Task; //awaits for the callback to be called without blocking the UI.
client.Close();

关于c# - 从不同线程调用时,WCF Duplex 回调方法从不执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33602528/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com