0

I'm using a WCF service in a .Net 4.0 WPF application and I'm observing a call to a WCF service blocking updates on the UI thread even though it has the UseSynchronizationContext = false defined on the service class.

The following code does not block the UI when the Thread.Sleep() is included but when the call to api.GetFieldExpressionAssemblies() is included instead it blocks updates to the UI.

This code is being executed on a background thread and has been scheduled using the Reactive extensions method ObserveOn() with the task pool scheduler.

.ObserveOn(Scheduler.TaskPool)
.Select(x =>
{
    var api = factory.Create();
    using (new Duration())
    {
        //Thread.Sleep(5000);
        //return new Dictionary<string, string[]>();
        return ExtractIntellisense(api.GetFieldExpressionAssemblies().Single());
    }
})

Rx version = 1.0.10621.2, this is an old version of Rx and I'm aware of issues with scheduling work onto the task pool with this version of the Rx scheduler, but the fact the Thread.Sleep() does not block the UI thread indicates this is not the issue.

Any ideas why this might happen?

AwkwardCoder
  • 24,893
  • 27
  • 82
  • 152
  • What does `api.GetFieldExpressionAssemblies()`? Maybe it's executing its code in the UI thread. Do you have the associated code? – ken2k Dec 12 '13 at 14:17
  • it is the call to the WCF service which returns a collection of 'assemblies' – AwkwardCoder Dec 12 '13 at 14:24
  • Occam's Razor would suggest that either (1) `return ExtractIntellisense(api.GetFieldExpressionAssemblies().Single())` is doing work on the UI thread (2) Something on the UI thread is waiting for the result (3) The UI thread is not blocked by this code, the blocking happens afterwards when the result is processed. Can you provide some clarification? And maybe code showing how the RX is used? – James World Dec 12 '13 at 15:49
  • You said *"it has the UseSynchronizationContext = false defined on the service class"* - that's only relevant for a `CallbackBehavior` on the client proxy class. Is that what you mean? If not, how are you invoking the service? Via APM methods (BeginXXX, EndXXX), Task style, or synchronously? If you are using a callback and haven't specified the CallbackBehavior(UseSynchronizationContext=false) then the synchronizationcontext will be established on the thread that calls `Open()` on the proxy or the thread that makes the first call on the proxy if its not explicitly opened. – James World Dec 13 '13 at 10:26
  • Also, you might want to try using the Spy method to check all threads are as expected. http://stackoverflow.com/questions/20220755/how-can-i-see-what-my-reactive-extensions-query-is-doing – James World Dec 13 '13 at 10:28
  • James thanks for the info, I am using a client proxy class provided by another team. – AwkwardCoder Dec 13 '13 at 11:10
  • Hmmm. Might be worth cracking it open in Reflector and seeing what it's doing. – James World Dec 13 '13 at 13:22
  • James - already been in reflector, and the service is marked with the attribute set to false for UseSynchronizationContext. I'm in the middle of a merge at the moment, but defnitely going to use your Spy rx extension method to see whats going on, will report back when I have more info. – AwkwardCoder Dec 13 '13 at 14:02
  • The code posted doesn't do anything on its own. Show where you subscribe to the observable. – Brandon Dec 13 '13 at 21:24

3 Answers3

0

My psychic debugger says that if you wrapped this code in a Task.Run it would work. Rx is working fine here, but WCF is capturing a synchronization context at the point you're creating the Observable, which is probably the UI thread, because WCF is dumb.

Ana Betts
  • 73,868
  • 16
  • 141
  • 209
0

I have been able to prove the problem is not with binding the results from the WCF because the following code still block the UI even though the results returned from the WCF are not actually returned from the Rx chain.

This points to trying what Paul suggested.

.ObserveOn(SchedulerService.TaskPool)
.Select(x =>
{
   var api = factory.Create();
   using (new Duration())
   {
      var intellisenseDictionary = ExtractIntellisense(api.GetFieldExpressionAssemblies().Single());
      //return intellisenseDictionary;

      return new Dictionary<string, string[]>();
 }
AwkwardCoder
  • 24,893
  • 27
  • 82
  • 152
0

So the answer as usual is a simple one, someone had changed the WCF service ConcurrencyMode to Single, requests were being processed in a serial manner.

Which backs up what I was seeing - but with a small difference, the UI thread was not blocked I could still move the window round and it was being redrawn, just the data was not appearing.

WCF sucks!

AwkwardCoder
  • 24,893
  • 27
  • 82
  • 152