Serializing/Deserializing Objects That You Can't Annotate

2,276 views
Skip to first unread message

DLC

unread,
Nov 17, 2011, 8:17:11 AM11/17/11
to mongodb-csharp
Hi Everyone,

Worked with mongodb via pymongo for a while, but first time working
with the C# driver.

I'm wondering if anyone has a nice solution to serialize/deserialize
objects without being able to annotate the classes themselves (from an
external dll)?

Right now the object I can't annotate is serialized to XML via default
C# XML serializer and stored, but it's a weird solution because it
requires storing the AssemblyQualifiedName to deserialize it later.
I'm wondering if there's a smarter way to do this. Would something
like JSON.NET be more useful?


Robert Stam

unread,
Nov 17, 2011, 9:40:31 AM11/17/11
to mongodb...@googlegroups.com
The C# driver has built-in support for serialization. Take a look at:


If a class has a no-argument constructor and public read-write properties it can probably be serialized as is without any annotations required.

The serialization tutorial shows how anything that can be done with an annotation can also be done in setup code without annotations, precisely to handle scenarios like you describe where you don't control the source code of the objects (or perhaps just want to keep them free of dependencies on your persistence layer).

DLC

unread,
Nov 17, 2011, 10:59:19 AM11/17/11
to mongodb-csharp
Thanks Robert, I read that before and it's useful.
The issue is that there is a serious type hierarchy, so I wanted a
more generic way to serialize any class that might come in without
havingto state each class explicitly, but map any of their properties
that are .net data types automatically. I'm doing it right now but am
not happy with the xml serialization. I don't need to query on the
Properties that aren't .net data types necessarily (the ones that are
serialized), but I still need to persist them.
I could perhaps generate the code to do the mappings automatically, or
just use:
if (!BsonClassMap.IsClassMapRegistered(typeof(MyClass))) {   //
register class map for MyClass}and cycle through the properties each
time I serialize a new class to make sure I have their Properties
types registered as well.
I imagine I would have to worry about the class dependencies/ordering
I register them in either way.

Robert Stam

unread,
Nov 17, 2011, 11:05:48 AM11/17/11
to mongodb...@googlegroups.com
The C# driver automaps classes for you, so in general you don't need to do anything. You only need to get involved if you need to override the automapping in some way. For those classes where automapping is sufficient just read and write them and let the driver take care of the mapping automatically.

Automapping is done on demand the first time you try to serialize or deserialize an instance of a class, so the only thing to keep in mind is that if you want to take control of the mapping you must do so before reading or writing any values of that type.

DLC

unread,
Nov 17, 2011, 1:11:46 PM11/17/11
to mongodb-csharp
Ok, I tried using Generics on the collections as you said it would
automap but when I try just using a dictionary<string, object> object
I get:

System.NotSupportedException : Subclass must implement GetDocumentId.

var collection = _cache.GetCollection<Dictionary<string,
object>>(collectionName);
var docs = collection.FindAllAs<Dictionary<string,object>>();
if (docs.Size() == 0)
{
var positions = base.GetAllPositionsAsOf(dtAsOf, sFilter);
collection.InsertBatch<Dictionary<string,object>>(positions); <----
On this line
return positions;
}
else
{
var positions = new List<Dictionary<string, object>>();

foreach(var doc in docs)
{
positions.Add(doc);
}
return positions;

Robert Stam

unread,
Nov 17, 2011, 1:22:04 PM11/17/11
to mongodb...@googlegroups.com
The root object (the one passed as a type argument to FindAs) can't be a Dictionary. It has to be a class that includes an _id field. You could wrap your Dictionary like this:

public class MyClass {
    public ObjectId Id;
    public Dictionary<string, object> Values;
}

If what you are trying to do is process a document without creating a class then use BsonDocument instead of Dictionary. BsonDocument is very similar to Dictionary but it maps strings to BsonValues and has some additional BSON related functionality.

DLC

unread,
Nov 17, 2011, 2:25:29 PM11/17/11
to mongodb-csharp
Well then the problem with discriminators and the whole class
hierarchy that I do not manage comes into play --

MongoDB.Bson.BsonSerializationException : Unknown discriminator value
'TheirClass'.

and ends up with me having to register all of the classes. and
managing the heirarchy


I have been using the BsonDocument method, and serializing the objects
to strings using C#'s native serializer, but wanted to do it a nicer
way. It seems like there isn't one.

Robert Stam

unread,
Nov 17, 2011, 2:51:40 PM11/17/11
to mongodb...@googlegroups.com
Well, there is a catch-22 involved here. The serializer can't recognize discriminators it doesn't know about...

You can still use automap, but you *at least* have to tell the serializer that you intend to use a class. To automap a class you can use either:

    BsonClassMap.RegisterClassMap<Person>();
    BsonClassMap.RegisterClassMap(typeof(Person));

They are equivalent, but the second might be more useful to you if you are trying to register a bunch of classes that you might go find using Reflection.

DLC

unread,
Nov 17, 2011, 9:24:47 PM11/17/11
to mongodb-csharp
I eneded up creating a script to generate all of classes I need, but
in the end it still wouldn't work as they contain a struct property,
and it seems as though I can't write a serializer for structs as they
pass by value not reference.

I noticed the JIRA ticket https://jira.mongodb.org/browse/CSHARP-94
here so I guess I'll just have to stick with my method for now.
Reply all
Reply to author
Forward
0 new messages