-
Type: Bug
-
Resolution: Done
-
Priority: Major - P3
-
Affects Version/s: 1.8.3
-
Component/s: Serialization
-
None
Ever since I registered creator for my persistable model, I can no longer deserialize it from database. Driver keeps throwing BsonInternalException from BsonCreatorMap.CreateInstance method.
I found this code fragment to be responsible for this:
else if (!_defaultValues.TryGetValue(elementName, out argument)) { // shouldn't happen unless there is a bug in ChooseBestCreator throw new BsonInternalException(); }
After further investigation I found the root reason for this problem. It's the BsonCreatorMap.Freeze method, which contains following code fragment:
// compare MetadataTokens because ReflectedTypes could be different (see p. 774-5 of C# 5.0 In a Nutshell) var memberMap = allMemberMaps.FirstOrDefault(m => m.MemberInfo.MetadataToken == argument.MetadataToken); if (memberMap == null) { var message = string.Format("Member '{0}' is not mapped.", argument.Name); throw new BsonSerializationException(message); } elementNames.Add(memberMap.ElementName);
This code matches class property (MemberInfo) to registered BsonMemberMap just by memberInfo.MetadataToken. However, as specified MSDN documentation, this token is not globally unique. It's only unique within specific module.
In my case I have two types:
- Person defined in BaseAssembly
- Employee (extends Person) defined in AnotherAssembly
Two types, defined in two assemblies, in one inheritance hierarchy. Two different properties were assigned the same MetadataToken:
- Person.Code
- Employee.Name
This line:
var memberMap = allMemberMaps.FirstOrDefault(m => m.MemberInfo.MetadataToken == argument.MetadataToken);
caused the same member map (for Person.Code property) to be added twice (once for Person.Code and once for Employee.Name), due to the same metadata tokens.
So _elementNames has 2x Code property. CreateInstance iterates over this collection, removing objects from values dictionary. First iteration is OK (removes actual value for Code property). Second iteration can't find value for duplicated Code property and throws BsonInternalException.