好吧,我在我的智慧結束這件事情。我有一個WCF雙工服務。這裏是架構是如何工作的:WCF從另一個線程調用時,永不執行WCF雙工回調方法
- 客戶端打開到端點的連接,並提供一個回調實現
- 該服務採用這一請求並執行其他線程上的一些東西(可以1秒可能爲2分鐘,這是我沒有使用異步操作)
- 當處理完成後,它會調用客戶端
問題是,當服務調用回調,似乎什麼也沒有發生回調的原因。沒有錯誤,沒有任何東西。經過進一步調查,我發現服務器跟蹤中有一個例外:
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;
}
這就是服務調用客戶端回調的地方(這個方法在另一個線程f上執行)黑山初始請求上所做的一個):
ISubmissionCallback callback = submissions[submissionResult.ExecutionId];
callback.SubmissionProcessed(submissionResult);
服務行爲:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
正如你可以在提交時看到,服務店鋪的回調在字典中,用一個id配對,它稍後用來檢索回調並調用它。我相信它失敗的原因是因爲我試圖在另一個線程上做到這一點。
編輯: 我加入了Ping操作的服務,調用另一個線程,掛起3秒鐘,然後調用客戶端上的傍功能。
public void Ping()
{
var callback = OperationContext.Current.GetCallbackChannel<ISubmissionCallback>();
Task.Run(() =>
{
System.Threading.Thread.Sleep(3000);
callback.Pong();
});
}
客戶端: 類節目 { 靜態無效的主要(字符串[]參數) { NetHttpBinding結合=新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)
{
}
}
}
這實際上工作成功。我設法在客戶端收到我的答案。我現在正式完全失去了。
作爲一個測試,你可以嘗試在你的線程上回調一個非常基本的方法,例如一個沒有像'Ping'這樣的參數並且看看會發生什麼?在建立連接後嘗試限制頻道上的任何其他通信/操作,以便簡化重新創建。 – wal
你是否保持對服務器端連接的引用? (不只是回調參考) – wal
你是否用'submissionCompletionSource.Task.Wait();'阻塞UI線程?此外,爲什麼當你有'等待'這行時,你會叫'Wait',難道你不願意'await submissionCompletionSource.Task'嗎? –