Mongo C# Driver and ObjectID JSON String Format in .NET Core

Viewed 6771

Problem

I have a collection of dynamic data. I want to get it back like this:

{
  _id: "58b454f20960a1788ef48ebb"
  ... 
}

Attempts

Here are a list of approaches that do not work:

This

await resources = _database.GetCollection<BsonDocument>("resources")
    .Find(Builders<BsonDocument>.Filter.Empty)
    .ToListAsync();

return Ok(resources);

Yields

[[{"name":"_id","value":{"bsonType":7,"timestamp":1488213234,"machine":614561,"pid":30862,"increment":16027323,"creationTime":"2017-02-27T16:33:54Z","rawValue":{"timestamp":1488213234,"machine":614561,"pid":30862,"increment":16027323,"creationTime":"2017-02-27T16:33:54Z"},"value":{"timestamp":1488213234,"machine":614561,"pid":30862,"increment":16027323,"creationTime":"2017-02-27T16:33:54Z"}}}]]

This

await resources = _database.GetCollection<BsonDocument>("resources")
    .Find(Builders<BsonDocument>.Filter.Empty)
    .ToListAsync();

return Ok(resources.ToJson());

Yields

[{ "_id" : ObjectId("58b454f20960a1788ef48ebb"), ... }]

This

await resources = _database.GetCollection<BsonDocument>("resources")
    .Find(Builders<BsonDocument>.Filter.Empty)
    .ToListAsync();

return Ok(resources.ToJson(new JsonWriterSettings() { OutputMode = JsonOutputMode.Strict }));

Yields

[{ "_id" : { "$oid" : "58b454f20960a1788ef48ebb" }, ... }]

This

await resources = _database.GetCollection<BsonDocument>("resources")
    .Find(Builders<BsonDocument>.Filter.Empty)
    .ToListAsync();

return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(resources));

Yields

"Newtonsoft.Json.JsonSerializationException: Error getting value from 'AsBoolean' on 'MongoDB.Bson.BsonObjectId'. ---> System.InvalidCastException: Unable to cast object of type 'MongoDB.Bson.BsonObjectId' to type 'MongoDB.Bson.BsonBoolean'

And changing BsonDocument to dynamic yields the same results.

I have also tried registering a serializer according to the docs. I really like this solution since I always want my ObjectIds in a reasonable format and not in something unusable. I would like to get this working if possible.

This

_client = new MongoClient(clientSettings); 
_database = _client.GetDatabase(_settings.DatabaseName); 
BsonSerializer.RegisterSerializer(new ObjectIdSerializer());

...

class ObjectIdSerializer : SerializerBase<ObjectId>
{
    public override ObjectId Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        return context.Reader.ReadObjectId();
    }

    public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, ObjectId value)
    {
        context.Writer.WriteString(value.ToString());
    }
}

Had no effect on any of the above results.

3 Answers

A "terrible" way of solving this is to convert your BsonDocument to a Dictionary in case your object is a plain object.

    [HttpGet]
    public async Task<IActionResult> Get()
    {
        var items = (await collection.Find(new BsonDocument()).ToListAsync());

        var obj = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(items.ToJson());

        return Ok(obj);
    }

This method is simple to code but I see a lot of overhead for conversions.

The best way is to change the Asp.Net serializer to return the "items.ToJson()" as the response Content without trying to parse it.

The old (but gold) HttpRequestMessage enables it. (I can't have time to create a sample to share here now)

Related