C# MongoDB complex class serialization

后端 未结 3 1700
鱼传尺愫
鱼传尺愫 2020-12-30 15:45

I\'m working with C# MongoDB driver and I have this rather complex JSON struct to save:

{
    \"name\" : \"value\",
    \"age\": 1,
    \"isFemale\": true,
          


        
相关标签:
3条回答
  • 2020-12-30 16:15

    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.

    0 讨论(0)
  • 2020-12-30 16:19

    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

    0 讨论(0)
  • 2020-12-30 16:29

    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 :-)

    0 讨论(0)
提交回复
热议问题