C# deserialize from BsonDocument to an abstract object type

3,365 views
Skip to first unread message

mciureanu

unread,
May 20, 2011, 9:24:44 AM5/20/11
to mongodb-user
Hello everyone.

I have problems deserializing a BsonDocument to an abstract class
called, let's say, Animal, with concrete classes Dog and Cat. I use
BsonKnownTypes attribute correctly within the Animal class, I've
tested it when using Animal as collection. But now I want to use the
an Animal instance as embedded object. Calling
BsonSerializer.Deserialize<Animal>(doc) doesn't work. How can I
convert from a BsonDocument to an object, without knowing the exact
type? (I can check for the "_t" field, but I guess there is already
something made which I don't know how to use)

Actually what I am trying to accomplish is having a mongo collection
with objects like this:

public class Element
{
public DateTime Created {get;set;}
public object OtherData {get;set;}
}

This type of class cannot be mapped (or at least i didn't succeed), so
i tired with BsonDocument instead of object:

public class Element
{
public DateTime Created {get;set;}
public BsonDocument OtherData {get;set;}
}

For specific elements, I just know at the runtime their types, for
example - Animal type, so I want in this case to deserialze the
BsonDocument into an Animal. Does anybody have any idea?
Thanks

Nat

unread,
May 20, 2011, 9:34:15 AM5/20/11
to mongod...@googlegroups.com
It should work.
- Your document needs to contain _t. What's your document you are trying to deserialize?
- Did you register all class hierarchies before trying to deserialize?

mciureanu

unread,
May 20, 2011, 9:43:26 AM5/20/11
to mongodb-user
You're right, I'm sorry - I was giving it the wrong document. The
document had a document with the right data... The exception message
"Cannot deserialize abstract object" or something like this gave me
the wron impression.
Thanks you very much.

Robert Stam

unread,
May 20, 2011, 10:12:08 AM5/20/11
to mongodb-user
Just to confirm that the following should work, though it should have
an Id field if it is going to be the root document stored in a
collection:

public class Element
{
public ObjectId Id {get;set;} // I added this
public DateTime Created {get;set;}
public object OtherData {get;set;}
}

If it doesn't work for you can we dig a little deeper?

mciureanu

unread,
May 20, 2011, 10:36:19 AM5/20/11
to mongodb-user
This also works. Don't know what happened.... I'm sorry
Thanks

Robert Stam

unread,
May 20, 2011, 10:51:42 AM5/20/11
to mongodb-user
I wrote up a quick test to verify that it really worked (of course we
have unit tests for all of this also, but I wanted to test your
scenario specifically).

Here's the program I wrote:

http://www.pastie.org/1931985

I decided it was worth sharing because it illustrates an important
point: before the BsonSerializer can deserialize a particular class
(say Animal) it must have first created a class map for that class
(and in the case of an abstract class like Animal for its known types
as well).

The gotcha is: if the first thing your program does is serialize an
instance of Animal, the class maps are created automatically. But if
the first thing your program does is deserialize an instance of
Animal, you need to make the class known to the serializer first.
Checkout the EnsureKnownTypesAreRegistered helper method. You only
need to inform the serializer of classes it wouldn't otherwise
discover automatically. Element will be discovered automatically
because it is the type of the collection. Cat and Dog will be
discovered automatically when LookupClassMap is called for Animal
because they are known types of Animal.
Reply all
Reply to author
Forward
0 new messages