7

System.Threading.Tasks を使用してバックグラウンドで WCF サービスを呼び出す WPF アプリケーションがあります。Task.ContinueWith を使用して、サービス呼び出しの結果を WPF UI スレッドに返します。私の問題は、継続は UI スレッドで実行されますが、実行すると SynchronizationContext.Current が null になることです。最初のタスクで WCF 呼び出しをコメント アウトして、同じコードを実行できます。継続は UI スレッドで行われ、予想どおり DispatcherSynchronizationContext が使用されます。

WCF プロキシは ChannelFactory を使用して生成され、wsHttpBinding を使用します。コールバック コントラクトはありません。関連するコードを以下に示します。

    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)
    { elided }

このコードをそのまま実行すると、ServiceContinuation は正しいスレッド (ManagedThreadID を使用して検証) で呼び出されますが、SynchronizationContext.Current は null です。サービス呼び出し (result = service.TheServiceMethod();) を行う 1 行をコメント アウトすると、DispatcherSynchronizationContext を使用して ServiceContinuation が正しく呼び出されます。

1 つの注意点 - SynchronizationContext は永久に失われるわけではありません - ボタンをもう一度クリックすると、ボタン クリック ハンドラーには正しい SynchronizationContext があります。

2 つのケースのスタック トレースを取得しました。いくつかの違いがあります。同一の部分はすべて省略し、異なるスタックの一番上に加えて、参照用にいくつかのフレームのみを含めました。

失敗 - WCF サービスを呼び出します

WpfContinuationsTest.MainWindow.ServiceContinuation
WpfContinuationsTest.MainWindow.<Button_Click>b__0
System.Threading.Tasks.Task`1+<>c__DisplayClass17.<ContinueWith>b__16
System.Threading.Tasks.Task.InnerInvoke
System.Threading.Tasks.Task.Execute
System.Threading.Tasks.Task.ExecutionContextCallback
System.Threading.ExecutionContext.runTryCode
System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup
System.Threading.ExecutionContext.RunInternal
System.Threading.ExecutionContext.Run
System.Threading.Tasks.Task.ExecuteWithThreadLocal
System.Threading.Tasks.Task.ExecuteEntry
System.Threading.Tasks.SynchronizationContextTaskScheduler.PostCallback

成功 - WCF サービスへの呼び出しがありません

WpfContinuationsTest.MainWindow.ServiceContinuation
WpfContinuationsTest.MainWindow.<Button_Click>b__0
System.Threading.Tasks.Task`1+<>c__DisplayClass17.<ContinueWith>b__16
System.Threading.Tasks.Task.InnerInvoke
System.Threading.Tasks.Task.Execute
System.Threading.Tasks.Task.ExecutionContextCallback
System.Threading.ExecutionContext.Run
System.Threading.Tasks.Task.ExecuteWithThreadLocal
System.Threading.Tasks.Task.ExecuteEntry
System.Threading.Tasks.SynchronizationContextTaskScheduler.PostCallback

唯一の違いが WCF クライアント サービス呼び出し (コールバック コントラクトなし) である場合、メイン スレッドでの継続に SynchronizationContext がある場合とない場合がある理由を知っている人はいますか?

4

1 に答える 1

7

Microsoft によると、これは TPL の既知のバグです。

http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/629d5524-c8db-466f-bc27-0ced11b441ba

于 2011-02-22T08:19:05.673 に答える