Friday, November 14, 2008

WCF service blocking when self-hosting (or How The ServiceBehavior's UseSynchronizationContext parameter saved me)

Today I was working on a feature in our application that uses WCF.  We wanted to make it possible to run the service piece in-process or as a service with minimal changes.  This is quite easy with WCF using the ServiceModelEx library from the iDesign crew.  Simply reference the ServiceModelEx.dll and wherever you'd normally create your WCF client proxy, just use the following code instead:

  1. Dim channel = InProcFactory.CreateInstance(Of TServiceImpl, TServiceInterface)()

However, when I ran this code the first call on the client proxy hung and timed out.  I started digging into why it was timing out.  Eventually I remembered reading about WCF's ability to use a SynchronizationContext with the ServiceBehaviorAttribute.  Essentially WCF will use a SynchronizationContext to manage some of the threading issues that arise from writing a WCF service and/or client.  (See more here).  It gets even better when you are hosting a WCF service within a Windows Forms application.  In that case the WCF service will grab the WinForm SynchronizationContext that manages threading of the UI thread.

It turns out that was exactly my problem.  Using the InProcFactory (which uses the Named Pipe binding to host the service implementation in the same process as the client) my service was being hosted in my WinForms application.  This caused the default WCF behaviour of attaching to the UI thread's SynchronizationContext to occur.  When I called my WCF service, the service blocked because the WCF client proxy was invoked from the UI.  When the timeout occurred and the client-side had finished with the UI thread, the service happily proceeded to execute (which was far too late at this point).

The Solution

The solution turns out to be extremely easy.  The ServiceBehaviorAttribute can be applied to your WCF service implementation.  One of the parameters to that is "UseSynchronizationContext".  Set that to false on your service and the service will create it's own SynchronizationContext and your client will no longer block when hosting the service in process.

  1. ServiceBehavior(ConcurrencyMode:=ConcurrencyMode.Reentrant, UseSynchronizationContext:=False)> _
  2. Public Class MyService
  3.              Implements IMyService

3 comments:

Anonymous said...

ran into the same annoying issue.
thank you for the solution.

James Jensen said...

Thank you so much for posting this fix.

Anonymous said...

Thank you very much for the solution.
You have saved my day! I've been trying to fix the blocking issue for several days and didn't know what to look for.