OK, I'm on my end with this thing. I have a WCF duplex service. Here's how the architecture works:
- The client opens a connection to the endpoint and provides a callback implementation
- The service accepts this request and does some things on other threads (maybe 1 second may be 2 minutes, for this reason I do not use async operations)
- When processing is completed, it calls the client callback
The problem is that the service is calling this callback, nothing seems to be happening. No mistake, nothing. Upon further investigation, I found an exception in the server trace:
The I/O operation has been aborted because of either a thread exit or an application request
This happens immediately after trying to make a callback.
The client never receives a response or does not close. All that happens is that, since the initial request is executed in a thread other than the main one, it simply waits there forever to complete this thread.
The strangest thing is that if I try to call a callback in the operation that the client calls without switching to another thread, everything works fine - the callback was called successfully, which makes me think that I configured the service correctly, but there is a problem with the thread / deadlock.
This is how I call the service:
SubmissionServiceClient client = CreateClientInstance();
client.Open();
Guid executionId = await client.SubmitAsync(submission);
submissionCompletionSource.Task.Wait();
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;
}
This is a callback operation:
public void SubmissionProcessed(SubmissionResultDto result)
{
submissionCompletionSource.TrySetResult(result);
}
This is a service operation that the client calls:
public Guid Submit(SubmissionDto submission, ISubmissionCallback callback)
{
ExecutionDto execution = new ExecutionDto()
{
Id = Guid.NewGuid(),
Submission = submission
};
RequestExecution(execution);
submissions.Add(execution.Id, callback);
return execution.Id;
}
And here the service calls the client callback (this method is executed in a different thread from the one on which the initial request was made):
ISubmissionCallback callback = submissions[submissionResult.ExecutionId];
callback.SubmissionProcessed(submissionResult);
Service Behavior:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Reentrant)]
, , , . , , , , .
EDIT:
Ping , , 3 , Pong .
public void Ping()
{
var callback = OperationContext.Current.GetCallbackChannel<ISubmissionCallback>();
Task.Run(() =>
{
System.Threading.Thread.Sleep(3000);
callback.Pong();
});
}
: { static void Main (string [] args) { NetHttpBinding = NetHttpBinding(); binding.WebSocketSettings.TransportUsage = WebSocketTransportUsage.Always; EndpointAddress endpointAddress = new EndpointAddress ( "ws://localhost: 9080/SubmissionRouter" ); InstanceContext instanceContext = new InstanceContext ( 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)
{
}
}
}
. . .