Wednesday, March 23, 2011

Synchronization Contexts in WCF

One of the more useful features of the Windows® Communication Foundation (WCF) is its reliance on the Microsoft® .NET Framework synchronization context to marshal calls to the service instance (or to a callback object). This mechanism provides for both productivity-oriented development and for powerful extensibility. In this column, I describe briefly what synchronization contexts are and how WCF uses them, and then proceed to demonstrate various options for extending WCF to use custom synchronization contexts, both programmatically and declaratively. In addition to seeing the merits of custom synchronization contexts, you will also see some advanced .NET programming as well as WCF extensibility techniques.

What Are .NET Synchronization Contexts?

The .NET Framework 2.0 introduced a little-known feature called the synchronization context, defined by the class SynchronizationContext in the System.Threading namespace:
 public delegate void SendOrPostCallback(object state);
public class SynchronizationContext
{
   public virtual void Post(SendOrPostCallback callback,object state);
   public virtual void Send(SendOrPostCallback callback,object state);
   public static void SetSynchronizationContext
(SynchronizationContext context);
   public static SynchronizationContext Current
   {get;}
   //More members
}

The synchronization context is stored in the thread local storage (TLS). Every thread created with the .NET Framework 2.0 may have a synchronization context (similar to an ambient transaction) obtained via the static Current property of SynchronizationContext. Current may return null if the current thread has no synchronization context. The synchronization context is used to bounce a method call between a calling thread and a target thread or threads, in case the method cannot execute on the original calling thread. The calling thread wraps the method it wants to marshal to the other thread (or threads) with a delegate of the type SendOrPostCallback, and provides it to the Send or Post methods, for synchronous or asynchronous execution respectively. You can associate a synchronization context with your current thread by calling the static method SetSynchronizationContext.

By far, the most common use of a synchronization context is with UI updates. With all multithreaded Windows technologies, from MFC to Windows Forms to WPF, only the thread that created a window is allowed to update it by processing its messages. This constraint has to do with the underlying use of the Windows message loop and the thread messaging architecture. The messaging architecture creates a problem when developing a multithreaded UI application—you would like to avoid blocking the UI when executing lengthy operations or receiving callbacks. This, of course, necessitates the use of worker threads, yet those threads cannot update the UI directly because they are not the UI thread.

In order to address this problem in the .NET Framework 2.0, the constructor of any Windows Forms-based control or form checks to see if the thread it is running on has a synchronization context, and if it does not have one, the constructor attaches a new synchronization context (called WindowsFormsSynchronizationContext). This dedicated synchronization context converts all calls to its Post or Send methods into Windows messages and posts them to the UI thread message queue to be processed on the correct thread. The Windows Forms synchronization context is the underlying technology behind the commonly used BackgroundWorker helper control.

WCF and Synchronization Contexts

By default, all WCF service calls (and callbacks) execute on threads from the I/O Completion thread pool. That pool has 1,000 threads by default, none of them under the control of your application. Now imagine a service that needs to update some user interface. The service should not access the form, control or window directly because it is on the wrong thread. To deal with that, the ServiceBehaviorAttribute offers the UseSynchronizationContext property, defined as:

 [AttributeUsage(AttributeTargets.Class)]
public sealed class ServiceBehaviorAttribute : ...
{
   public bool UseSynchronizationContext 
   {get;set;}
   //More members 
}

The default value of UseSynchronizationContext is set to true. To determine which synchronization context the service should use, WCF looks at the thread that opened the host. If that thread has a synchronization context and UseSynchronizationContext is set to true, then WCF automatically marshals all calls to the service to that synchronization context. There is no explicit interaction with the synchronization context required of the developer. WCF does that by providing the dispatcher of each endpoint with a reference to the synchronization context, and the dispatcher uses that synchronization context to dispatch all calls.

For example, suppose the service MyService (defined in Figure 1) needs to update some UI on the form MyForm. Because the host is opened after the form is constructed, the opening thread already has a synchronization context, and so all calls to the service will automatically be marshaled to the correct UI thread.

   Figure 1 Using the UI Synchronization Context

 [ServiceContract]
interface IMyContract
{...}
class MyService : IMyContract
{
   /* some code to update MyForm */ 
}
class MyForm : Form
{...}
static class Program
{
   static void Main()
   {
      Form form = new MyForm();//Sync context established here
      ServiceHost host = new ServiceHost(typeof(MyService));
      host.Open();
      Application.Run(form);
      host.Close(); 
   }
}

If you were to simply open the host in Main and use the code generated by the Windows Forms designer, you would not benefit from the synchronization context, since the host is opened without it present:

 //No automatic use of synchronization context
static void Main()
{
   ServiceHost host = new ServiceHost(typeof(MyService));
   host.Open();
   Application.Run(new MyForm());//Synchronization context 
                                 //established here
   host.Close(); 
}

Service Custom Synchronization Context
Utilizing a custom synchronization context by your service or resources has two aspects to it: implementing the synchronization context and then installing it.

Read more: MSDN magazine