Search code examples
c#mongodbserializationbson

Passing Type information to MongoDB so it can deserialize interface types properly?


I have a class that I serialize into MongoDB as a BsonDocument, this class also happens to have a property of type IMyInterface.

public interface IMyInterface
{
    String Name { get; set; }
}

public class MyClass
{
    public IMyInterface IntRef { get; set; }
}

During a MyClass object instances lifetime IntRef can reference multiple different classes that implement IMyInterface. Upon serialization I have found that all of the data from the class that IntRef points to is also serialized in the BsonDocument, not just Name.

Upon deserialization though BsonDocument.Deserialize does not have information about the Type of the class that IntRef points to and throws an exception. How can I provide the Type information to my call to Deserialize?

I also have a naive work around where I Deserialize the part of the document that is IntRef, which works well. Given the proper class Type, BsonDocument.Deserialize returns the object instance of that Type. Though the issue here is that I still cannot Deserialize the top level BsonDocument representing MyClass because it still holds the sub document pertaining to IntRef. Is there a way to tell Deserialize to ignore part of BsonDocument? I had the idea to just setting MyBsonDocument[SubDocName] = null though its non-nullable.


Solution

  • As a result of MyClass pointing to an interface type, which could then hold any class' Bson that implements that interface, we have to tell MongoDB the type of class' that can at the end of that (all of the) interface. It can then infer from the classes that it knows of how to deserialize certain BsonDocuments containing those class' Bson.

    public interface IMyInterface
    {
        String Name { get; set; }
    }
    
    public class MyIntImpl : IMyInterface
    {
        public String Name { get; set; }
    }
    
    public class MyClass
    {
        public IMyInterface IntRef { get; set; }
    
        public MyClass()
        {
            IntRef = new MyIntImpl();
        }
    }
    
    // When starting up MongoDB
    private void RegisterClasses()
    {
        BsonClassMap.RegisterClassMap<MyIntImpl>();
    }
    

    By adding the class MyIntImpl to the BsonClassMap it now knows how to deserialize Bson from that class type. You just have to make sure you keep the map filled with classes that implement interfaces you might serialize.

    Some reference links: High to low level overview of C# MongoDB serialization, an SO post that outlines the solution.