djskinner
djskinner

Reputation: 8125

WCF Duplex Callback in WPF Application: Dispatcher.BeginInvoke doesn't execute the delegate

I'm trying to set up a simple duplex service whereby clients connect to the server. Any connected client may execute the BookAdded service operation. When this occurs the server is supposed to raise a callback on all connected clients to notify them of the change.

The callback seems to be working fine except that the callback operation needs to run something on the UI thread using Dispatcher.BeginInvoke.

In my case Console.WriteLine("Callback thread") gets executed buy Console.WriteLine("Dispatcher thread") does not. What is the reason for this?

My service contract:

public interface ICallback
{
    [OperationContract(IsOneWay = true)]
    void BookAdded(string bookId);
}

[ServiceContract(
    CallbackContract = typeof(ICallback), 
    SessionMode = SessionMode.Required)]
public interface IService
{
    [OperationContract]
    bool BookAdded(string bookId);
}

My service implementation:

[ServiceBehavior(
    UseSynchronizationContext = false,
    InstanceContextMode = InstanceContextMode.PerSession, 
    ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class MyService : IService
{
    public bool BookAdded(string bookId)
    {
        try
        {
            Console.WriteLine("Client Added Book " + bookId);

            foreach (ICallback callback in connectedClients)
            {
                callback.BookAdded(bookId);
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        return true;
    }
}

My client implementation:

[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyCallBack: ICallback, IDisposable
{
    private Dispatcher theDispatcher;
    private InstanceContext context;
    private WcfDuplexProxy<IService> proxy;

    [ImportingConstructor]
    public MyCallBack()
    {  
        theDispatcher = Dispatcher.CurrentDispatcher;
        context = new InstanceContext(this);
        proxy = new WcfDuplexProxy<IService>(context);

        proxy.Connect();
    }

    public IService Service
    {
        get
        {
            return proxy.ServiceChannel;
        }
    }

    public void CallServiceOperation()
    {
        Service.BookAdded("BOOK1234");
    }

    public void BookAdded(string bookId)
    {
        Console.WriteLine("Callback thread");
        theDispatcher.BeginInvoke(new Action(() => { Console.WriteLine("Dispatcher thread"); }));
    }

    public void Dispose()
    {
        Service.Disconnect();
        proxy.Close();
    }

Upvotes: 1

Views: 4128

Answers (2)

Paul Zhou
Paul Zhou

Reputation: 193

I think I have encountered similar issue with yours. I resolved it with a new thread to invoke Dispatcher.beginInvoke. As I understand, the UI thread sends request to Service, the Service will invoke callback contract that implements in your client during the service operation. So if in callback operation it invoke a control of UI thread which is pending to wait response from Service operation. This is why the client is deadlocked. So you can try code below: Thread th=new Thread(new ThreadStart(()=>{Console.WriteLine("Callback thread");
theDispatcher.BeginInvoke(new Action(() => { Console.WriteLine("Dispatcher thread"); }));
})); th.Start();

Upvotes: 0

gjvdkamp
gjvdkamp

Reputation: 10526

What I suspect is happening is that the UI thread is still blocked on the original call to the server witch hasn't finished yet. I think if you change the concurrencymode on the client to reentrant it could work. . What you need to do is set [CallbackBehavior(UseSynchronizationContext = false)] on the callback.

This article explains this issue quite well.

GJ

Upvotes: 3

Related Questions