losik123
losik123

Reputation: 590

Serializing weak typed BsonDocument to JSON in controller

I have an issue with the MongoDB driver. I'm writing a .Net Core web api that is consumed by a JavaScript frontend. There is a Parent and Child class. In the child class I wanted to implement a weakly typed field where I could put in any JSON value, just a regular key/value store. That's my setup:

public class Child
{
    public int Id { get; set; }

    public string Type { get; set; }

    public BsonDocument Properties { get; set; }
}
public class Parent
{
   [BsonId]
   [BsonRepresentation(BsonType.ObjectId)]
   public string Id { get; set; }

   public List<Child> Children { get; set; }
}

In the database a parent element may look as follows:

{
    "_id" : 1,
    "Children" : [
    {
        "_id" : 1,
        "Type" : "TEXT",
        "Properties" : {
            "Width" : 100,
            "Height" : 100,
            "Color" : "red"
        }
   }]
}

The reading from the database is working that way. MongoDB is deserializing the data and everything is ok. The issue I have is on the controller level. That's the fairly simple Controller code:

[HttpGet]
public ActionResult<List<Parent>> Get()
{
   // _parentRepository.Get() is returning a List<Parent> read from the DB
   return _parentRepository.Get();
}

But when I send a request to the API that's the result I'm getting:

{
    "id" : 1,
    "children" : [
    {
        "id" : 1,
        "type" : "TEXT",
        "properties" : [
            {
                "name": "Width",
                "value": 100
            },
            {
                "name": "Height",
                "value": 100
            },
            {
                "name": "Color",
                "value": "red"
            }
       ]

   }]
}

So as you can see the BsonDocument is serialized like a dictionary where it's a list of key/value pairs. I would prefer to have a flat JSON there, so a representation exactly like in the database.

I tried with JsonResult and an explicit cast to Controller.Json(), but the result was the same.

NOTE: I'm using .NET Core 2.2! I know 3.0 has introduced some changes related to JSON, but haven't been able to update the project yet.

Thanks!

Upvotes: 1

Views: 362

Answers (1)

mickl
mickl

Reputation: 49985

This is just the way Newtonsoft.Json serializes BsonDocument type into string. You can easily fix that introducing your own serializer and running BsonDocument.ToJson() method:

public class BsonToJsonConverter : JsonConverter<BsonDocument>
{
    public override BsonDocument ReadJson(JsonReader reader, Type objectType, BsonDocument existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        return BsonDocument.Parse(token.ToString());
    }

    public override void WriteJson(JsonWriter writer, BsonDocument value, JsonSerializer serializer)
    {
        writer.WriteRawValue(value.ToJson());
    }
}

And decorating your type:

public class Child
{
    public int Id { get; set; }

    public string Type { get; set; }

    [JsonConverter(typeof(BsonToJsonConverter))]
    public BsonDocument Properties { get; set; }
}

Upvotes: 2

Related Questions