diff --git a/src/MongoDB.Bson/Serialization/BsonSerializer.cs b/src/MongoDB.Bson/Serialization/BsonSerializer.cs index 52dabe5e7f6..0f493a00f21 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializer.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializer.cs @@ -14,6 +14,7 @@ */ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; @@ -41,7 +42,8 @@ public static class BsonSerializer private static HashSet __discriminatedTypes = new HashSet(); private static BsonSerializerRegistry __serializerRegistry; private static TypeMappingSerializationProvider __typeMappingSerializationProvider; - private static HashSet __typesWithRegisteredKnownTypes = new HashSet(); + // ConcurrentDictionary is being used as a concurrent set of Type. The values will always be null. + private static ConcurrentDictionary __typesWithRegisteredKnownTypes = new ConcurrentDictionary(); private static bool __useNullIdChecker = false; private static bool __useZeroIdChecker = false; @@ -679,23 +681,15 @@ public static void Serialize( // internal static methods internal static void EnsureKnownTypesAreRegistered(Type nominalType) { - __configLock.EnterReadLock(); - try - { - if (__typesWithRegisteredKnownTypes.Contains(nominalType)) - { - return; - } - } - finally + if (__typesWithRegisteredKnownTypes.ContainsKey(nominalType)) { - __configLock.ExitReadLock(); + return; } __configLock.EnterWriteLock(); try { - if (!__typesWithRegisteredKnownTypes.Contains(nominalType)) + if (!__typesWithRegisteredKnownTypes.ContainsKey(nominalType)) { // only call LookupClassMap for classes with a BsonKnownTypesAttribute #if NET452 @@ -709,7 +703,10 @@ internal static void EnsureKnownTypesAreRegistered(Type nominalType) LookupSerializer(nominalType); } - __typesWithRegisteredKnownTypes.Add(nominalType); + // NOTE: The nominalType MUST be added to __typesWithRegisteredKnownTypes after all registration + // work is done to ensure that other threads don't access a partially registered nominalType + // when performing the initial check above outside the __config lock. + __typesWithRegisteredKnownTypes[nominalType] = null; } } finally