WCF Duplex callback method never executes when called from another thread

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(); //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;
}

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); //Queues the execution of the operation
            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)
        {

        }
    }
}

. . .

+4
1

submissionCompletionSource.Task.Wait();, . WCF , , CallbackBehaviorAttribute

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

    public void SubmissionProcessed(SubmissionResultDto result)
    {

    }
}

.

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();
+3

Source: https://habr.com/ru/post/1614991/


All Articles