2

我遇到了一个我不太理解的问题。

该问题与客户端线程之间的同步有关,但我找不到其根本原因。我创建了一个小演示来模拟这个问题,所以它会更容易解释。

服务联系人:

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ITestServiceCallback))]
public interface ITestService
{
    [OperationContract]
    Task RegisterAsync();

    [OperationContract]
    Task UnRegisterAsync();

    [OperationContract]
    int Test1(int i);
}

回调合约:

public interface ITestServiceCallback
{
    [OperationContract(IsOneWay = true)]
    void TestCallback(int value);
}

服务实施:

调用Test1方法时的服务将使用提供给方法的值引发回调Test1

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class TestService : ITestService
{
    private readonly HashSet<ITestServiceCallback> _callbacks = new HashSet<ITestServiceCallback>();

    public Task RegisterAsync()
    {
        Console.WriteLine("Registering Callback, Thread: {0}", Thread.CurrentThread.ManagedThreadId);
        var callbackProxy = OperationContext.Current.GetCallbackChannel<ITestServiceCallback>();
        _callbacks.Add(callbackProxy);
        return Task.CompletedTask;
    }

    public Task UnRegisterAsync()
    {
        Console.WriteLine("Unregistering Callback, Thread: {0}", Thread.CurrentThread.ManagedThreadId);
        var callbackProxy = OperationContext.Current.GetCallbackChannel<ITestServiceCallback>();
        bool removed = _callbacks.Remove(callbackProxy);
        Console.WriteLine("Callback was{0} successfully removed", removed ? "" : " not");
        return Task.CompletedTask;
    }

    public int Test1(int i)
    {
        Console.WriteLine("Working on server, Test1, Thread: {0}", Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(500);

        raiseCallback(i);

        Console.WriteLine("Finished on server, Test1, Thread: {0}", Thread.CurrentThread.ManagedThreadId);

        return i;
    }

    private void raiseCallback(int value)
    {
        foreach (var callback in _callbacks)
        {
            try
            {
                callback.TestCallback(value);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Callback calling failed in server: {0}", ex);
            }
        }
    }
}

客户代码:

客户端首先注册到服务器的回调(注意异步注册调用 -这就是问题)然后调用Test1. 这里的调用Test1永远不会返回

var callBack = new ClientCallback();
var client = DuplexChannelFactory<ITestService>.CreateChannel(callBack, _defaultBinding, _defaultEndpointAddress);
using (client as IDisposable)
            {
                await client.RegisterAsync(); // client.RegisterAsync.Wait();
                Console.WriteLine("Client Thread: {0}", Thread.CurrentThread.ManagedThreadId);
                try
                {
                    int res = client.Test1(5);
                    Console.WriteLine("Test1 was called, Server Result: {0}", res);


                }
                finally
                {
                    await client.UnRegisterAsync();
                }
            }




[CallbackBehavior(UseSynchronizationContext = false)]
    class ClientCallback : ITestServiceCallback
    {
        public void TestCallback(int value)
        {
            Console.WriteLine("Callback Called, Value: {0}, Thread: {1}", value, Thread.CurrentThread.ManagedThreadId);
        }
    }
  • RegisterAsync同步调用(使用.Wait())时,调用Test1不会死锁。
  • 在服务器中调用Test1通行证没有任何问题。
  • 使用的绑定是 NetNamedPipeBinding:

    绑定_defaultBinding = new NetNamedPipeBinding { MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue, ReceiveTimeout = TimeSpan.MaxValue, SendTimeout = TimeSpan.MaxValue, CloseTimeout = TimeSpan.MaxValue };

我认为将UseSynchronizationContext属性设置为false(在 theServiceBehaviourAttribute和 in 中CallbackBehaviourAttribute)应该可以解决这个问题。

4

0 回答 0