5

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)

1 Answer 1

3

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

Sign up to request clarification or add additional context in comments.

3 Comments

Deserialization is not an issue. This is an 'append only' collection, and in the rare condition where something is read back, it will be through custom projections. Anyway - custom serializers isn't a good option, since one point of this is to being able to add 'whatever' to the log.
I had kind of a workaround going, by serializing the data as json with json.net first, and then ask mongo to create a bsondocument of the json. It kinda worked, but not an optimal solution...
@Vegar Perhaps your workaround is the best solution. MongoDrive could add whatever to teh collection, but it want to be sure to be possible to get it back in exact the sam form, and for that is uses typedescriptors.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.