Search code examples
c#.netwcfwindowsformshost

Callbacks on SynchronizationContext


Trying to wrap my head around why a windows Form implementing a callback is not working.

What I'm trying to do:

  • A button is pressed and a service is called.
  • The service calls back to the form (the function has IsOneWay = true)
  • The form updates GUI accordingly

Having UseSynchronizationContext on false and calling Invoke on the GUI members works fine:

[CallbackBehavior(UseSynchronizationContext = false)]
public class DeliveryClient : System.Windows.Forms.Form, ICallback
{        
        public void ServiceCallback(string system, string state, string extraInfo)
        {
            if (state == "start")
            {
                Invoke((MethodInvoker)delegate { picBox.Visible = true; });
            }
            else
            {
                Invoke((MethodInvoker)delegate { picBox.Visible = false; });
            }
        }
}

But UseSynchronizationContext = true and directly calling the members does not:

[CallbackBehavior(UseSynchronizationContext = true)]
public class DeliveryClient : System.Windows.Forms.Form, ICallback
{        
        public void ServiceCallback(string system, string state, string extraInfo)
        {
            if (state == "start")
            {
                picBox.Visible = true;
            }
            else
            {
                picBox.Visible = false;
            }
        }

Neither does using SyynchronizationContext literally

SynchronizationContext.Current.Send(_=> picBox.Visible = true, null);

Should the second and third version also work? The callback is called OneWay so the service continues after callback.


Solution

  • Is your Form class really the implementation of your WCF service client callback, as WCF knows it (i.e. not just something you delegate to from the WCF client)? If not, then you've put the [CallbackBehavior] attribute in the wrong place. As the documentation states:

    The CallbackBehaviorAttribute must be applied to the class that implements the callback contract

    If it is the implementation of your client callback, then without a good Minimal, Complete, and Verifiable code example I'm afraid I wouldn't be able to say why the attribute isn't having the expected effect. But I would be able to say that, if that is indeed the case, your code is designed poorly. Combining your UI with your service client callback implementation violates a number of OOP principles for healthy code, but most importantly the Separation of Concerns principle.

    As far as this goes:

    SynchronizationContext.Current.Send(_=> picBox.Visible = true, null);
    

    That's not how you should use SynchronizationContext. The Current property returns the context for the currently running thread. By the time you need to call Send(), it's too late to retrieve the context. You need to store SynchronizationContext.Current when you create your object, in the thread where you want delegates invoked by Send() to be executed (and of course, that thread has to have a useful context, such as found in the main UI thread of a Winforms program).

    If the above does not give you enough information to get your code working, please improve the question by providing a good MCVE that reliably reproduces the problem.