Ответ 1
Проблема исправлена в .NET 4.5 RC (только что протестирована). Поэтому я предполагаю, что это ошибка в .NET 4.0. Кроме того, я предполагаю, что эти сообщения ссылаются на одну и ту же проблему:
- Как SynchronizationContext.Current основного потока становится нулевым в приложении Windows Forms?
- 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);
}
}
Проблема только воспроизводится, когда мы попадаем в предложение else, которое вызывает RunInternal. Это связано с тем, что 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;
}
}
Итак, для моего конкретного случая это произошло потому, что строка `executeContext.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
было true. Вот этот код:
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;
}
}
Для меня это вернулось, потому что HasUserData было правдой. Вот этот код:
internal bool HasUserData
{
get { return ((m_Datastore != null) && (m_Datastore.Count > 0));}
}
Для меня в m_DataStore будут элементы из-за моего вызова Diagnostics.Trace.CorrelationManager.StartLogicalOperation("LogicalOperation");
В целом, похоже, что существует несколько разных способов получить ошибку для воспроизведения. Надеюсь, этот пример поможет другим людям определить, запущены ли они в эту же ошибку или нет.