简体   繁体   中英

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();
    }

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

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();
Thread th=new Thread(new ThreadStart(()=>{Console.WriteLine("Callback thread");
theDispatcher.BeginInvoke(new Action(() => { Console.WriteLine("Dispatcher thread"); }));
})); th.Start();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM