该问题已在 .NET 4.5 RC 中修复(刚刚测试过)。所以我认为这是 .NET 4.0 中的一个错误。
另外,我猜测这些帖子引用了同一个问题:
-
Windows 窗体应用程序中主线程的 SynchronizationContext.Current 如何变为 null? https://stackoverflow.com/questions/4659257/how-can-synchronizationcontext-current-of-the-main-thread-become-null-in-a-windo?rq=1
- http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/629d5524-c8db-466f-bc27-0ced11b441ba http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/629d5524-c8db-466f-bc27-0ced11b441ba
那真不幸。现在我必须考虑解决方法。
Edit:
通过调试 .Net 源代码,我对问题何时重现有了更好的了解。以下是 ExecutionContext.cs 中的一些相关代码:
internal static void Run(ExecutionContext executionContext, ContextCallback callback, Object state, bool ignoreSyncCtx)
{
// ... Some code excluded here ...
ExecutionContext ec = Thread.CurrentThread.GetExecutionContextNoCreate();
if ( (ec == null || ec.IsDefaultFTContext(ignoreSyncCtx)) &&
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
SecurityContext.CurrentlyInDefaultFTSecurityContext(ec) &&
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
executionContext.IsDefaultFTContext(ignoreSyncCtx))
{
callback(state);
}
else
{
if (executionContext == s_dummyDefaultEC)
executionContext = s_dummyDefaultEC.CreateCopy();
RunInternal(executionContext, callback, state);
}
}
仅当我们进入调用 RunInternal 的“else”子句时,该问题才会重现。这是因为 RunInternal 最终替换了 ExecutionContext,这会改变当前 SynchronizationContext 的内容:
// Get the current SynchronizationContext on the current thread
public static SynchronizationContext Current
{
get
{
SynchronizationContext context = null;
ExecutionContext ec = Thread.CurrentThread.GetExecutionContextNoCreate();
if (ec != null)
{
context = ec.SynchronizationContext;
}
// ... Some code excluded ...
return context;
}
}
因此,对于我的具体情况,这是因为 `executionContext.IsDefaultFTContext(ignoreSyncCtx)) 行返回 false。这是代码:
internal bool IsDefaultFTContext(bool ignoreSyncCtx)
{
#if FEATURE_CAS_POLICY
if (_hostExecutionContext != null)
return false;
#endif // FEATURE_CAS_POLICY
#if FEATURE_SYNCHRONIZATIONCONTEXT
if (!ignoreSyncCtx && _syncContext != null)
return false;
#endif // #if FEATURE_SYNCHRONIZATIONCONTEXT
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
if (_securityContext != null && !_securityContext.IsDefaultFTSecurityContext())
return false;
#endif //#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK
if (_logicalCallContext != null && _logicalCallContext.HasInfo)
return false;
if (_illogicalCallContext != null && _illogicalCallContext.HasUserData)
return false;
return true;
}
对我来说,由于以下原因而返回 false_logicalCallContext.HasInfo
是真的。这是代码:
public bool HasInfo
{
[System.Security.SecurityCritical] // auto-generated
get
{
bool fInfo = false;
// Set the flag to true if there is either remoting data, or
// security data or user data
if(
(m_RemotingData != null && m_RemotingData.HasInfo) ||
(m_SecurityData != null && m_SecurityData.HasInfo) ||
(m_HostContext != null) ||
HasUserData
)
{
fInfo = true;
}
return fInfo;
}
}
对我来说,这返回 true,因为 HasUserData 是 true。这是代码:
internal bool HasUserData
{
get { return ((m_Datastore != null) && (m_Datastore.Count > 0));}
}
对我来说,由于我调用, m_DataStore 中将包含项目Diagnostics.Trace.CorrelationManager.StartLogicalOperation("LogicalOperation");
总之,看起来有几种不同的方法可以让错误重现。希望这个示例能够帮助其他人确定他们是否遇到了同样的错误。