Can't serialize BsonDocument to Json from MVC3 using official C # driver

My web client is sending Json. MongoDB is practically Json. This should be easy, but I am tying to nodes fighting the C # driver in MVC3. There seems to be no easy way to avoid working in C # classes. I would have thought it would be easy to just pass the Json back and forth with a little filtering. Its how I struggle with ORM and I don't want to be.

Anyway, I (without hesitation) built my data model in C #, I am using Json.Net and my serialization code looks like this:

My serialization code for JsonResult:

public override void ExecuteResult(ControllerContext context)
{
    ...
    var serializedObject = JsonConvert.SerializeObject(Data, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
}

      

I can't for the life of me figure out how to do this without mapping objects. Thus, I have a controller action;

public JsonResult test() 
{
    var col = _db.GetCollection<Project>("myCollection");

    var jsText = System.IO.File.ReadAllText(System.IO.Path.Combine(HttpContext.Server.MapPath("~/Controllers"), "MapReducers.js"));
    string map_cashflow = new Regex(@"//function map_cashflow(.*?)//end", RegexOptions.Singleline).Match(jsText).Captures[0].ToString();
    string reduce_cashflow = new Regex(@"//function reduce_cashflow(.*?)//end", RegexOptions.Singleline).Match(jsText).Captures[0].ToString();

    var mr = col.MapReduce(map_cashflow, reduce_cashflow);
    return Json(mr, JsonRequestBehavior.AllowGet); 
}

      

This now works when I serialize cursors elsewhere (for some reason), but now I understand that the above fails because it tries to serialize the actual BsonDocument, not the underlying data. I get an error when it tries to serialize the first field as some other type, usually trying to convert a string or date to AsBoolean (). It's a shame that the driver can't let the document serialize a little more easily.

I had a similar problem while trying to use BsonDocument to represent the dynamic part of my object graph. I figured this is better than a json string, but of course it won't serialize. I ended up using a dictionary <> which is fine.

I have also tried them with similar results;

return Json(mr.GetResults());
return Json(mr.GetResults()).ToArray();

      

So, I have also tried the following, I have seen people achieve success,

var jsonText = mr.ToJson(); // empty
var jsonText = mr.GetResults().toJson(); // Exception: No serializer found for type System.Collections.IEnumerator.

      

All I want to do is drop what looks almost the same as Json, but I can't figure out how to serialize it. Is this the only way?

var resultsObj = mr.GetResultsAs<ResultsClass>();

      

If so, it sucks. I don't want to create statically typed classes just to host the results documents. This ORM has gone crazy! I don't need to go in and out of C # objects, the driver is indeed more of a hindrance than a help. I think I would rather have Json like it.

+3


source to share


2 answers


I see no reason why you would need to create an Object Model to do this unless MVC3 dictates this requirement to you. Using BsonDocument and serializing straight to JSON string should be fine. It's hard to skip much of your message, but when the MapReduce call is zeroed out, the GetResults () method returns an IEnumerable <BsonDocument> that you can easily convert to JSON. Here's a simple test:

IEnumerable<BsonDocument> results = new BsonDocument[] 
{
    new BsonDocument("x", 1),
    new BsonDocument("x", 2)
};
var json = results.ToJson();

      

When I run this code, the json variable ends with the following content:

[{ "x" : 1 }, { "x" : 2 }]

      



In particular, I am not getting the exception you mentioned. Can you make sure you are using a sufficiently newer version of the C # driver and if you still get an exception from the full stack trace?

Part of the problem can arise when mixing and matching the BsonDocument with a JSON serializer that is not part of the C # driver. Third party JSON serializers (like the Json method that you use that returns a JsonResult) usually impose their own restrictions on what they can and cannot serialize. Thus, the problems you are facing appear to be external to the C # MongoDB driver.

Sorry, I really don't know enough about MVC3 and how it expects to return results in JSON to say a lot about this.

+3


source


So I wrote a one way plugin for Json.Net that will allow me to serialize BsonDocuments using the toJson () method on the document itself. This is not ideal because now I have two different follower stacks,

public class BsonDocumentConverterPlugin : Newtonsoft.Json,JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        BsonDocument bsonDoc = (BsonDocument)value;
        writer.WriteRaw(bsonDoc.ToJson());
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException("Serialisation back to Bson not supported in this converter");
    }

    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(BsonDocument));
    }
}

      

and in my override JsonResult;

        var serializedObject = JsonConvert.SerializeObject(Data, Formatting.None, 
                new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore,
                                             Converters = new List<JsonConverter>() { new BsonDocumentConverterPlugin() }
                });

      

Unfortunately this does not work for my MapReduce result set, which has multiple results as it does not serialize them as an array and skips commas, which results in invalid json no matter which serialization method I use. BsonDocument.ToJson () also writes invalid json values ​​for dates. When strictly written ISODate () and in JavaScript / TenGen it writes newDate (). Both of these are causing my browser to disconnect.



So in the end, I had to resort to building an object graph,

    public class MrResultsetCashflow
    {
        [MongoDB.Bson.Serialization.Attributes.BsonId]
        public DateTime date { get; set; }
        public FinancialItem value;
    }

      

and I go through the original MVC / json.net serialization stack;

        var f = mr.GetResultsAs<MrResultsetCashflow>();
        return Json(f, JsonRequestBehavior.AllowGet); 

      

+1


source







All Articles