17

Im working on a project that use .NET Razor and mongodb. I would like to do something like this:

@{
    var feeds = DP.Database.GetCollection("feeds").FindAll();
}
<ul>
    @foreach (dynamic feed in feeds)
    {
        <li>@feed.message - @feed.from.name</li>
    }
</ul>

However, the current mongodb C# driver FindAll() return collection of BsonDocument which does not support dynamic object. Anybody know a .NET 4 dynamic supported mongodb C# driver?

Thanks a lot

5 Answers 5

18

I created a straight-forward extension to the MongoDB driver that re-serializes the BSON document using Json.NET and deserializes it as a dynamic. By including the following class, you can simply convert your MongoDB queries to dynamic like this

dynamic obj = collection.FindOneByIdAs<BsonDocument>(someObjectId).ToDynamic();

Extension class:

public static class MongoDynamic
{
    private static System.Text.RegularExpressions.Regex objectIdReplace = new System.Text.RegularExpressions.Regex(@"ObjectId\((.[a-f0-9]{24}.)\)", System.Text.RegularExpressions.RegexOptions.Compiled);
    /// <summary>
    /// deserializes this bson doc to a .net dynamic object
    /// </summary>
    /// <param name="bson">bson doc to convert to dynamic</param>
    public static dynamic ToDynamic(this BsonDocument bson)
    {
        var json = objectIdReplace.Replace(bson.ToJson(), (s) => s.Groups[1].Value);
        return Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json);
    }
}

Be sure to reference Newtonsoft.Json.dll (http://james.newtonking.com/projects/json-net.aspx)

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

1 Comment

Using bson.ToJson(new JsonWriterSettings {OutputMode = JsonOutputMode.Strict}) removes the need for all the Regex processing to remove Mongo specific Json methods.
14

Currently, there is no support for dynamic in the MongoDB driver. This is because it is based on .NET 3.5. However, since a .NET 4.0 assembly can reference a .NET 3.5 assembly, it is possible for you to write a IBsonSerializationProvider and an IBsonSerializer in .NET 4.0 to support dynamics.

We, 10gen, are looking at doing this in the future. I have spiked some support at https://github.com/craiggwilson/mongo-csharp-driver/tree/dynamic if you want to take a look. There are most definitely bugs, but it shows that it is possible.

8 Comments

Thanks Craig, i found a way to make it work. check here groups.google.com/forum/?fromgroups#!topic/mongodb-user/…
Yes, I saw that. I will echo here for SO users. That works fine, but requires a low level modification to the core. The way I presented above is a side-load and accomplishes the same thing without modifying the core. Obviously, there are some differences, but it gets most of the way there. It is just a spike after all, so...
Take a look at MongoDB.Dynamic. It uses MongoDB official driver and take an approach of using interfaces with dynamics of C# 4.0.
Is this an official part of the driver now?
We are still working on documentation, but we support dynamic in the 2.0.0 driver (currently in rc0): mongodb.github.io/mongo-csharp-driver/2.0/what_is_new/#new-api
|
5

I have a clean solution using custom IBsonSerializer and Newtonsoft.Json.

Setup your custom serializer on the BsonClassMap

map.MapProperty(member => member.Data)
   .SetElementName("Data")
   .SetSerializer(new DynamicSerializer());

or on the property

[BsonSerializer(typeof(DynamicSerializer))]
public dynamic Data { get; set; }

And just include the following class

public class DynamicSerializer : IBsonSerializer
{
  #region Implementation of IBsonSerializer

  public object Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options)
  {
    return Deserialize(bsonReader, nominalType, null, options);
  }

  public object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType,
    IBsonSerializationOptions options)
  {
    if (bsonReader.GetCurrentBsonType() != BsonType.Document) throw new Exception("Not document");
    var bsonDocument = BsonSerializer.Deserialize(bsonReader, typeof(BsonDocument), options) as BsonDocument;
    return JsonConvert.DeserializeObject<dynamic>(bsonDocument.ToJson());
  }

  public IBsonSerializationOptions GetDefaultSerializationOptions()
  {
    return new DocumentSerializationOptions();
  }

  public void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
  {
    var json = (value == null) ? "{}": JsonConvert.SerializeObject(value);
    BsonDocument document = BsonDocument.Parse(json);
    BsonSerializer.Serialize(bsonWriter, typeof(BsonDocument), document,options); 
  }

  #endregion
}

InfoSlips - GlobalKinetic

1 Comment

can u give example on how to deserilze a single bsondocument into dynamic?
4

Just to build on Maximilian's answer. This will return a list of dynamics from any query.

    /// <summary>
    /// deserializes this BsonDocument cursor result to a list of .net dynamic objects
    /// </summary>
    /// <param name="cursor">cursor result to convert to dynamic</param>
    /// <returns></returns>
    public static List<dynamic> ToDynamicList(this MongoCursor<BsonDocument> cursor)
    {
        var dynamicList = new List<dynamic>();
        var list = cursor.ToList();
        for (int i = 0, l = list.Count; i < l; i++)
            dynamicList.Add(list[i].ToDynamic());

        return dynamicList;
    }

1 Comment

This seems redundant. You could just do cursor.Select(doc => doc.ToDynamic()). Add .ToList() if needed. In general, writing methods for which the framework already provides a good solution should be avoided.
0

Even though this is an old topic its still just as relevant today as when post was made, and I have yet to see any solutions out there that provides a simple solution for two way support, I have modified @Maximilian Scherer code so that it lets you convert to dynamic objects which easily let you save your Document again.

public static class MongoDynamic
{
    /// <summary>
    /// deserializes this bson doc to a .net dynamic object
    /// </summary>
    /// <param name="bson">bson doc to convert to dynamic</param>
    public static dynamic ToDynamic(this BsonDocument bson)
    {
        var json = bson.ToJson(new MongoDB.Bson.IO.JsonWriterSettings { OutputMode = JsonOutputMode.Strict });
        dynamic e =  Newtonsoft.Json.JsonConvert.DeserializeObject<ExpandoObject>(json);
        BsonValue id;
        if (bson.TryGetValue("_id", out id))
        {
            // Lets set _id again so that its possible to save document.
            e._id = new ObjectId(id.ToString());
        }
        return e;
    }
}

Example of usage:

// Get BsonDocument from db here
BsonDocument doc = ...

// Convert to dynamic.
var d = doc.ToDynamic();

// Lets add a none existant property.
d.Name = "test";

// Assuming you already have your collection set up
collection.Save(new BsonDocument(d));

Comments

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.