locked
Task.ContinueWith from WCF Client Call Has no SynchronizationContext RRS feed

  • Question

  • I have a WPF application that makes service calls to a WCF service, using a ChannelFactory generated proxy.  I'm using wsHttpBinding, and no callback contract.  For some potentially long-running service calls, I make the service call on a background thread using System.Threading.Tasks, then use Task.ContinueWith to update the UI from the background thread.  The issue I'm seeing as that, although the continuation does run on the main UI thread (verified using the managed thread ID), during the execution of the continuation, SynchronizationContext.Current is null on the UI thread.

     

    MainWindow.xaml:

     

    <Window x:Class="WcfContinuationsTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="Auto" />
          <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        
        <Button Click="Button_Click" Grid.Column="0">
          <TextBlock Text="Test" />
        </Button>
    
        <TextBlock Grid.Column="1" Text="" Name="_textResult"/>
      </Grid>
    </Window>
    

    MainWindow.xaml.cs:

     private TaskScheduler _uiScheduler;
    
      public MainWindow()
      {
        InitializeComponent();
        _uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
      }
    
      private void Button_Click(object sender, RoutedEventArgs e)
      {
        var serviceTask = new Task<Int32>(ServiceCallWrapper, 
          CancellationToken.None, 
          TaskCreationOptions.None);
    
        var continueTask = serviceTask.ContinueWith(result => ServiceContinuation(result.Result),
                              CancellationToken.None,
                              TaskContinuationOptions.OnlyOnRanToCompletion, 
                              _uiScheduler);
    
        serviceTask.Start();
      }
    
      private Int32 ServiceCallWrapper()
      {
        Int32 result = 0;
    
        var service = {elided - initializes service using ChannelFactory };
        result = service.TheServiceMethod();
        service.Close();
    
        return result;
      }
    
      private void ServiceContinuation(Int32 result)
      { 
           if(SynchronizationContext.Current == null)
          {
            _textResult.Text = "No SynchronizationContext";
          }
          else
          {
            _textResult.Text = "SynchronizationContext exists";
          }
      }
    

    If I run this code, as is, SynchronizationContext.Current will be null when ServiceContinuation is called (even though it is running on the UI thread).  If I simply comment out the "result = service.TheServiceMethod();" line, when ServiceContinuation is called, SynchronizationContext.Current is a DispatcherSynchronizationContext as expected.  

     

    Is there something about WCF that would cause this, or is it a strange interaction between WCF and Tasks?  I can fix the problem by using the Dispatcher or the SynchronizationContext directly to Post the result to the UI thread, but it seems like using Tasks this way should work.

     

    I'm posting this in the WCF forum, as the issue only occurs when making a WCF service call.

    Sunday, February 20, 2011 3:36 AM

Answers

  • I verified with the TPL team that this is potentially caused by a known bug in .NET threading handling. This will be fixed in a future release.
    Lante, shanaolanxing This posting is provided "AS IS" with no warranties, and confers no rights.
    Windows Azure Technical Forum Support Team Blog
    • Marked as answer by Yi-Lun Luo Friday, February 25, 2011 9:00 AM
    Tuesday, February 22, 2011 4:37 AM

All replies

  • Hello, why do you need to obtain synchronization context? If you want to queue tasks to the UI thread, you can use Dispatcher.BeginInvoke. In your scenario, WPF, WCF, TPL, all manipulate the synchronization context, so there's no guarantee you'll get the same synchronization context in every place.
    Lante, shanaolanxing This posting is provided "AS IS" with no warranties, and confers no rights.
    Windows Azure Technical Forum Support Team Blog
    Monday, February 21, 2011 6:05 AM
  • In this case, although it's a WPF application, there are some WinForms controls as well.  In one specific case, a new WinForms control gets created in the Task continuation, and creates a WindowsFormsSynchronizationContext, on the UI thread; after that, things get really strange.  

    In most other situations, the absence of a SynchronizationContext is not that critical; my question is what causes the difference?  

    I have a TaskScheduler, created from a DispatcherSynchronizationContext, that schedules a continuation on the UI thread.  The continuation does correctly run on the UI thread; however, why does the UI thread have a SynchronizationContext in the one case, and not in the other?

    Monday, February 21, 2011 3:50 PM
  • I verified with the TPL team that this is potentially caused by a known bug in .NET threading handling. This will be fixed in a future release.
    Lante, shanaolanxing This posting is provided "AS IS" with no warranties, and confers no rights.
    Windows Azure Technical Forum Support Team Blog
    • Marked as answer by Yi-Lun Luo Friday, February 25, 2011 9:00 AM
    Tuesday, February 22, 2011 4:37 AM
  • Thanks for the info!
    Tuesday, February 22, 2011 8:19 AM
  • Was it fixed (after 1 year)?
    Tuesday, March 13, 2012 12:53 PM
  • Tuesday, July 24, 2012 3:50 PM
  • More importantly here's a workaround:

    http://stackoverflow.com/questions/32455111/hooked-events-outlook-vsto-continuing-job-on-main-thread

    Thursday, April 6, 2017 7:42 PM