wcf icon indicating copy to clipboard operation
wcf copied to clipboard

Synchron calls after Asynchron calls with no result blocks forever

Open MJE-GTI opened this issue 1 year ago • 4 comments

Describe the bug When I call a sync WCF OperatinContract after an async OperationContract call with no result the synchron call is never resolved. If the perverious async call has a result this problem does not happen.

To Reproduce Create a WCF Service with Async Methods that returns somsthing (Test1Async) and one that returns nothing (Test2Async) and add a sync Method (Test3)

[ServiceContract]
public interface ITestService
{
    [OperationContract]
    Task<string> Test1Async(string text);

    [OperationContract]
    Task Test2Async(string text);

    [OperationContract]
    string Test3(string text);
}

Call the WCF Interface (see code below with comments)

private static async Task CallNetPipeBinding(string hostAddr)
{
    IClientChannel channel = null;

    var binding = new NetNamedPipeBinding();

    var factory = new ChannelFactory<ITestService>(binding, new EndpointAddress($"{hostAddr}/netPipe"));
    await Task.Factory.FromAsync(factory.BeginOpen, factory.EndOpen, TaskCreationOptions.None);
    try
    {
        ITestService client = factory.CreateChannel();
        channel = client as IClientChannel;
        await Task.Factory.FromAsync(channel.BeginOpen, channel.EndOpen, TaskCreationOptions.None);

        await client.Test1Async("Test");
        client.Test3("Test");// This call works because the perverious call returns something
        await client.Test2Async("Test");
        client.Test3("Test");// This call does not work becausee the pereverious call returns nothing
    }
    finally
    {
        factory.Close();
    }
}

Expected behavior Synchron calls after async call with no result don't block forever.

Additional context I think the problem is that the TaskCompletionSource withtout result is not created with TaskCreationOptions.RunContinuationsAsynchronously

TaskCompletionSource Creation with return Type: https://github.com/dotnet/wcf/blob/c7b4036b7f103d60df2b3fad4d5f8a74f2adfad4/src/System.ServiceModel.Primitives/src/System/ServiceModel/Channels/ServiceChannelProxy.cs#L318

https://github.com/dotnet/wcf/blob/c7b4036b7f103d60df2b3fad4d5f8a74f2adfad4/src/System.ServiceModel.Primitives/src/System/ServiceModel/Channels/ServiceChannelProxy.cs#L174

TaskCompletionSource Creation without return Type: https://github.com/dotnet/wcf/blob/c7b4036b7f103d60df2b3fad4d5f8a74f2adfad4/src/System.ServiceModel.Primitives/src/System/ServiceModel/Channels/ServiceChannelProxy.cs#L213

MJE-GTI avatar Aug 09 '24 09:08 MJE-GTI

Which package version are you using? I believe this was fixed in the last year or two.

mconnew avatar Aug 09 '24 23:08 mconnew

I believe this is the explanation of what's going on along with a workaround if you can't upgrade to a fixed version.
https://github.com/dotnet/wcf/issues/4946#issuecomment-1472715803
Basically you do this:

        await client.Test1Async("Test");
        client.Test3("Test");// This call works because the perverious call returns something
        await client.Test2Async("Test");
        await Task.Yield();
        client.Test3("Test");// This call does not work becausee the pereverious call returns nothing

mconnew avatar Aug 09 '24 23:08 mconnew

I tested it with the NuGet Packages Version 8.0.0 and with a local build of the master branch witch is less then a month old. The Example in https://github.com/dotnet/wcf/issues/4946#issuecomment-1472715803 only uses Tasks with a result Task<T> and this works without any problems for me. But if my Task does not have a result Task is doesn't work.

MJE-GTI avatar Aug 10 '24 08:08 MJE-GTI

@imcarolwang can you please create a PR and add unit tests for this?

HongGit avatar Aug 20 '24 21:08 HongGit