Home NetTcpBinding and async/await WCF blocking
Reply: 0

NetTcpBinding and async/await WCF blocking

user2913
1#
user2913 Published in May 21, 2018, 6:40 pm

We are creating a shared WCF channel to use with an async operation:

var channelFactory = new ChannelFactory<IWcfService>(new NetTcpBinding {TransferMode = TransferMode.Buffered});

channelFactory.Endpoint.Behaviors.Add(new DispatcherSynchronizationBehavior(true, 25));
var channel = channelFactory.CreateChannel(new EndpointAddress(new Uri("net.tcp://localhost:80/Service").AbsoluteUri + "/Test"));

This calls the following service:

[ServiceContract]
public interface IWcfService
{
    [OperationContract]
    Task<MyClass> DoSomethingAsync();
}

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]
public class WcfServiceImpl : IWcfService
{
    public Task<MyClass> DoSomethingAsync()
    {
        Thread.Sleep(4000);

        return Task.FromResult(new MyClass());
    }
}

[Serializable]
public class MyClass
{
    public string SomeString { get; set; }      
    public MyClass Related { get; set; }        
    public int[] Numbers { get; set; }
}

If we start 3 requests at once and simulate a long running task on the response:

        using ((IDisposable)channel)
        {
            var task1 = Task.Run(async () => await DoStuffAsync(channel));
            var task2 = Task.Run(async () => await DoStuffAsync(channel));
            var task3 = Task.Run(async () => await DoStuffAsync(channel));

            Task.WaitAll(task1, task2, task3);
        }
    }

    public static async Task DoStuffAsync(IWcfService channel)
    {
        await channel.DoSomethingAsync();

        Console.WriteLine("Response");

        // Simulate long running CPU bound operation
        Thread.Sleep(5000);

        Console.WriteLine("Wait completed");
    }

Then all 3 requests reach the server concurrently, it then responds to all 3 requests at the same time.

However once the response reaches the client it processes each in turn.

Response
// 5 second delay
Wait completed
// Instant
Response
// 5 second delay
Wait completed
// Instant
Response

The responses resume on different threads but only runs 1 per time.

If we use streaming instead of buffered we get the expected behaviour, the client processes all 3 responses concurrently.

We have tried setting max buffer size, using DispatcherSynchronizationBehaviour, different concurrency modes, toggling sessions, ConfigureAwait false and calling channel.Open() explicitly.

There seems to be no way to get proper concurrent responses on a shared session.

Edit

I have added an image of what I believe to be happening, this only happens in Buffered mode, in streamed mode the main thread does not block.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.310821 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO