我有一个 WPF 应用程序,它使用 System.Threading.Tasks 在后台调用 WCF 服务。我正在使用 Task.ContinueWith 将服务调用的结果返回给 WPF UI 线程。我的问题是,虽然延续确实在 UI 线程上运行,但当它运行时 SynchronizationContext.Current 为空。我可以运行相同的代码,在初始任务中注释掉 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 为空。如果我注释掉进行服务调用的单行 (result = service.TheServiceMethod();),则使用 DispatcherSynchronizationContext 正确调用 ServiceContinuation。
请注意 - SynchronizationContext 不会永久丢失 - 如果我再次单击按钮,则按钮单击处理程序确实具有正确的 SynchronizationContext。
我已经捕获了这两种情况的堆栈跟踪;他们有一些不同之处。我省略了所有相同的位,只包括它们不同的堆栈顶部,以及一些参考帧:
失败 - 调用 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,而在另一种情况下则不会?