Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# MongoDb serialization of Dictionary<string, object>

I have a collection in my database where I log events. Each type of event has a different set of data. I've defined this with the following class:

[CollectionName("LogEvent")]
public class LogEvent
{
    public LogEvent(string eventType)
    {
        EventType = eventType;
        EventData = new Dictionary<string, object>();
    }

    public string EventType { get; private set; }
    [BsonExtraElements]
    public IDictionary<string, object> EventData { get; private set; }
}

Now - this works pretty good to some extent. As long as the elements of the EventData dictionary are simple types...

var event = new LogEvent("JobQueues"){
    EventData = new Dictionary<string, object>(){
        { "JobId": "job-123" },
        { "QueueName": "FastLane" }
    }
}

_mongoCollection.InsertOne(event);

...I get mongo documents like

{
  _id: ObjectId(...),
  EventType: "JobQueued",
  JobId: "job-123",
  QueueName: "FastLane"
}

But as soon as I try to add a custom type to the dictionary, things stops working.

var event = new LogEvent("JobQueues"){
    EventData = new Dictionary<string, object>(){
        { "JobId": "job-123" },
        { "QueueName": "FastLane" },
        { "JobParams" : new[]{"param-1", "param-2"}},
        { "User" : new User(){ Name = "username", Age = 10} }
    }
}

This gives me errors like ".NET type ... cannot be mapped to BsonType."

If I remove the [BsonExtraElements] tag, and [BsonDictionaryOptions(DictionaryRepresentation.Document)] It will start serialize stuff without errors, but it will give me a complete different document which I don't like..

{
  _id: ObjectId(...),
  EventType: "JobQueued",
  EventData: {      
      JobId: "job-123",
      QueueName: "FastLane",
      User: {
       _t: "User",
       Name: "username",
       Age: 10
      },
      JobParams : {
       _t: "System.String[]",
       _v: ["param-1", "param-2"]
      }
   }
}

What I want, is the following result:

{
  _id: ObjectId(...),
  EventType: "JobQueued",
  JobId: "job-123",
  QueueName: "FastLane",
  User: {
    Name: "username",
    Age: 10
  },
  JobParams : ["param-1", "param-2"]
}

Does anyone know how to achieve that?

(I'm using the C# mongodriver v2.3)

like image 557
Vegar Avatar asked Oct 29 '22 13:10

Vegar


1 Answers

So works MongoDriver, because it needs information of the type to deserilize it back. What you could do, is to write and register your own CustomMapper for User class:

public class CustomUserMapper : ICustomBsonTypeMapper
{
    public bool TryMapToBsonValue(object value, out BsonValue bsonValue)
    {
        bsonValue = ((User)value).ToBsonDocument();
        return true;
    }
}

Somewhere on starting program:

BsonTypeMapper.RegisterCustomTypeMapper(typeof(User), new CustomUserMapper());

That will work, and i have managed to serialize your data exact as you want.

But: As you want to deserialize it back, you wil get your User class as Dictionary, because driver will have no information about hiow to deserialize it:

enter image description here

like image 125
Maksim Simkin Avatar answered Nov 02 '22 11:11

Maksim Simkin