Uploaded image for project: 'C# Driver'
  1. C# Driver
  2. CSHARP-910

BsonInternalException thrown in BsonCreatorMap.CreateInstance

    • Type: Icon: Bug Bug
    • Resolution: Done
    • Priority: Icon: Major - P3 Major - P3
    • 1.10, 2.0
    • Affects Version/s: 1.8.3
    • Component/s: Serialization
    • Labels:
      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:

      Unable to find source-code formatter for language: cs. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      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:

      Unable to find source-code formatter for language: cs. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      // 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:

      Unable to find source-code formatter for language: cs. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      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.

            Assignee:
            robert@mongodb.com Robert Stam
            Reporter:
            mythallar Norbert Grabowski
            Votes:
            2 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: