I\'m working with C# MongoDB driver and I have this rather complex JSON struct to save:
{
\"name\" : \"value\",
\"age\": 1,
\"isFemale\": true,
A simple way for dealing with this issue and not have to create additional properties, is registering a custom serializer.
ComplexTypeSerializer.cs
namespace MyNamespace.MongoDB.Serializers
{
public class ComplexTypeSerializer : SerializerBase<object>
{
public override object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var serializer = BsonSerializer.LookupSerializer(typeof(BsonDocument));
var document = serializer.Deserialize(context, args);
var bsonDocument = document.ToBsonDocument();
var result = BsonExtensionMethods.ToJson(bsonDocument);
return JsonConvert.DeserializeObject<IDictionary<string, object>>(result);
}
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
{
var jsonDocument = JsonConvert.SerializeObject(value);
var bsonDocument = BsonSerializer.Deserialize<BsonDocument>(jsonDocument);
var serializer = BsonSerializer.LookupSerializer(typeof(BsonDocument));
serializer.Serialize(context, bsonDocument.AsBsonValue);
}
}
}
And register it as per http://mongodb.github.io/mongo-csharp-driver/2.3/reference/bson/serialization/
BsonSerializer.RegisterSerializer(typeof(IDictionary<string, object>), new ComplexTypeSerializer());
or
BsonSerializer.RegisterSerializer(typeof(IList<IDictionary<string, object>>), new ComplexTypeSerializer());
The code below was tested with a simple IDictionary<string, object>
, not sure if it would work with IList<IDictionary<string, object>>
, however if it's not supported, you can create another custom serializer to support it.
Try to read the documentation more carefully, within the Serializer Registry section (http://mongodb.github.io/mongo-csharp-driver/2.4/reference/bson/serialization/#serializer-registry):
The serializer registry contains all the IBsonSerializers that have been registered. It can be accessed via the SerializerRegistry property of the static class BsonSerializer.
To register a serializer use either
BsonSerializer.RegisterSerializer(Type, IBsonSerializer)
or
BsonSerializer.RegisterSerializer<T>(IBsonSerializer<T>)
This will add them to
BsonSerializer.SerializerRegistry
Checkout the APIs for these classes here - http://mongodb.github.io/mongo-csharp-driver/2.4/apidocs/html/T_MongoDB_Bson_Serialization_BsonSerializer.htm
Found how to save the data to MongoDB here: Dictionary-to-BsonDocument conversion omitting _t field and extended it a bit so I thought to share the full solution.
Step #1:
In my class, I declared 2 members for each value:
// For the Hobbies object type:
[BsonIgnore] //ignore this value in MongoDB
public Dictionary<string, object> Hobbies { get; set; }
[JsonIgnore] //ignore this value in the response on Get requests
[BsonElement(elementName: "Hobbies")]
public BsonDocument HobbiesBson { get; set; }
/*********************************************************************/
// For the Collection object type:
[BsonIgnore] //ignore this value in MongoDB
public List<Dictionary<string, object>> Collection { get; set; }
[JsonIgnore] //ignore this value in the response on Get requests
[BsonElement(elementName: "Collection")]
public BsonArray CollectionBson { get; set; }
Step #2
In my WebAPI controller method for Post
[HttpPost]
public override async Task<IActionResult> Post([FromBody] Person person)
{
var jsonDoc = JsonConvert.SerializeObject(person.Hobbies);
person.HobbiesBson = BsonSerializer.Deserialize<BsonDocument>(jsonDoc);
jsonDoc = JsonConvert.SerializeObject(person.Collection);
person.CollectionBson = BsonSerializer.Deserialize<BsonArray>(jsonDoc);
//save
}
Step #3
In my Get
request I deserialize it back like this:
[HttpGet("{id?}")]
public override async Task<IActionResult> Get(string id = null)
{
var people = //get data from mongoDB
foreach (var person in people)
{
var bsonDoc = BsonExtensionMethods.ToJson(person.HobbiesBson);
person.Hobbies = JsonConvert.DeserializeObject<Dictionary<string, object>>(bsonDoc);
bsonDoc = BsonExtensionMethods.ToJson(person.CollectionBson);
person.Collection = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(bsonDoc);bsonDoc);
}
return Ok(people);
}
This solved my issue and I hope it can help others as well :-)