Search code examples
wcfduplex

Call request/reply method of duplex service freeze client until timeout occur


I have create a duplex WCF service tha return data from an external device to the client and allow also request/reply calls.

My problem is that the request/reply calls sometime freeze the client until timeout occurs.

These are the interfaces:

[ServiceContract(CallbackContract = typeof(ITimerServiceCallback), SessionMode = SessionMode.Required)]
public interface ITimerService
{
    [OperationContract]
    void StartTimer();

    [OperationContract]
    void StopTimer();

    [OperationContract]
    void DoOp();
}

public interface ITimerServiceCallback
{
    [OperationContract(IsOneWay = true)]
    void ReportTick(string now);
}

This is the implementation:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class TimerService : ITimerService
    {
        public TimerService()
        {
            _timer = new System.Timers.Timer() { Interval = 500 };
            _timer.Elapsed += Timer_Elapsed;
        }

        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            _context.GetCallbackChannel<ITimerServiceCallback>().ReportTick(DateTime.Now.ToString());
        }

        private readonly System.Timers.Timer _timer;
        private OperationContext _context;

        public void StartTimer()
        {
            _context = OperationContext.Current;
            _timer.Start();
        }

        public void StopTimer()
        {
            _timer.Stop();
        }

        public void DoOp()
        {
            System.Threading.Thread.Sleep(200);
        }
    }

Step to reproduce the problem: * call StartTimer * call DoOp (one or more time until the client freeze)

After one minute I have an timeout exception.


Solution

  • If I use the async/await from the client side all work fine.

    ex: the DoOp method is called in this way:

    private async void _btnDoOp_Click(object sender, EventArgs e)
    {
        _btnNoOp.Enabled = false;
        try {
            Task task = Task.Run(() => _client.DoOperation());
            await task;
        } catch (Exception ex) {
            MessageBox.Show(ex.Message);
        } finally {
            _btnNoOp.Enabled = true;
        }
    }