I have a problem in my application: At some point, the SynchronizationContext.Current becomes null for the main thread. I'm unable to reproduce the same problem in an isolated project. My real project is complex; it mixes Windows Forms and WPF and calls WCF Web Services. As far as I know, those are all systems that may interact with the SynchronizationContext.
This is the code from my isolated project. My real app does something that resembles that. However, in my real app the SynchronizationContext.Current is null on the main thread when the continuation task is executed.
private void button2_Click(object sender, EventArgs e)
{
if (SynchronizationContext.Current == null)
{
Debug.Fail("SynchronizationContext.Current is null");
}
Task.Factory.StartNew(() =>
{
CallWCFWebServiceThatThrowsAnException();
})
.ContinueWith((t) =>
{
//update the UI
UpdateGUI(t.Exception);
if (SynchronizationContext.Current == null)
{
Debug.Fail("SynchronizationContext.Current is null");
}
}, CancellationToken.None,
TaskContinuationOptions.OnlyOnFaulted,
TaskScheduler.FromCurrentSynchronizationContext());
}
What could cause the SynchronizationContext.Current of the main thread to become null?
Edit:
@Hans asked for the stack trace. Here it is:
at MyApp.Framework.UI.Commands.AsyncCommand.HandleTaskError(Task task) in d:\sources\s2\Framework\Sources\UI\Commands\AsyncCommand.cs:line 157 at System.Threading.Tasks.Task.c__DisplayClassb.b__a(Object obj) at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.Execute() at System.Threading.Tasks.Task.ExecutionContextCallback(Object obj) at System.Threading.ExecutionContext.runTryCode(Object userData) at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution) at System.Threading.Tasks.SynchronizationContextTaskScheduler.PostCallback(Object obj) at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner) at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) at System.Delegate.DynamicInvokeImpl(Object[] args) at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme) at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj) at System.Threading.ExecutionContext.runTryCode(Object userData) at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme) at System.Windows.Forms.Control.InvokeMarshaledCallbacks() at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.Run(Form mainForm) at MyApp.Framework.SharedUI.ApplicationBase.InternalStart() in d:\sources\s2\Framework\Sources\UI\SharedUI\ApplicationBase.cs:line 190 at MyApp.Framework.SharedUI.ApplicationBase.Start() in d:\sources\s2\Framework\Sources\UI\SharedUI\ApplicationBase.cs:line 118 at MyApp.App1.WinUI.HDA.Main() in d:\sources\s2\App1\Sources\WinUI\HDA.cs:line 63
SynchronizationContext.Current
to a_syncContext
variable. Then, in the task callback we doif (SynchronizationContext.Current == null) { SynchronizationContext.SetSynchronizationContext(_syncContext); }
. Did you look at @Dan's answer? I never got to trying it, which is why I still have not accepted his answer yet. If you tests it with .Net 4.5 and if it works, let me know and I'll accept Dan's answer. – Sylvain