无法使用官方C#驱动程序将BsonDocument从MVC3序列化为Json

时间:2012-04-05 22:03:07

标签: asp.net-mvc-3 model-view-controller mongodb json.net mongodb-.net-driver

我的网络客户端发送Json。 MongoDB几乎就是Json。它应该很简单,但我在与MVC3中的C#驱动程序打成平手。似乎没有简单的方法可以避免在C#类中工作。我曾经想过只需过滤一下就可以来回传递Json。就像我正在与ORM战斗而我不想成为。

无论如何,我(不情愿地)用C#构建我的数据模型,我正在使用Json.Net,我的序列化代码看起来像;

我的JsonResult的序列化代码是;

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

我不能为我的生活弄清楚如何在没有对象映射的情况下做到这一点。因此,我有一个控制器动作;

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); 
}

现在,当我在其他地方(由于某种原因)序列化游标时,这是有效的,但我现在明白上述失败,因为它试图序列化实际的BsonDocument而不是基础数据。我尝试将第一个字段序列化为其他类型时出错,通常是尝试将字符串或日期转换为AsBoolean()。令人遗憾的是,驱动程序不能让文档更容易序列化。

我在尝试使用BsonDocument来表示对象图的动态部分时遇到了类似的麻烦。我认为这比json字符串更好,但当然它不会序列化。我最终使用了Dictionary&lt;&gt;这很好。

我也尝试了类似的结果;

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

所以我也尝试了以下我见过人们取得了成功;

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

我想要做的就是扔回看起来几乎就像Json的东西,但我无法弄清楚如何序列化它。这是唯一的方法吗?

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

如果是这样,那很糟糕。我不想仅仅为了存放结果文档而构建静态类型的类。这是ORM疯了!我不需要进出C#对象,驱动程序确实更像是一种障碍而不是帮助。我想我宁愿让Json好好。

2 个答案:

答案 0 :(得分:3)

我没有看到任何理由为什么你需要为此创建一个对象模型,除非MVC3对你强加了这个要求。使用BsonDocument并直接序列化为JSON字符串应该没问题。通过调用MapReduce的结果很难理解你的大部分帖子,GetResults()方法返回一个IEnumerable&lt; BsonDocument&gt;类型的值,你应该能够轻松地转换为JSON。这是一个简单的测试:

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

当我运行此代码时,json变量最终得到以下内容:

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

特别是,我没有得到你提到的例外。你能否确保使用足够新版本的C#驱动程序,如果你仍然得到异常回复完整的堆栈跟踪?

部分问题可能来自混合和匹配BsonDocument与不属于C#驱动程序的JSON序列化程序。第三方JSON序列化程序(如您使用的Json方法返回JsonResult)通常会对它们可以和不能序列化的内容施加自己的约束。因此,您遇到的问题似乎是MongoDB C#驱动程序的外部问题。

很抱歉,我对MVC3以及它希望如何将结果转换回JSON以了解更多内容时,我真的不太了解。

答案 1 :(得分:1)

所以,我为Json.Net编写了一个单向插件,允许我使用文档本身的toJson()方法序列化BsonDocuments。它并不理想,因为我现在有两个不同的串行器堆栈;

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));
    }
}

并在我的JsonResult覆盖中;

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

不幸的是,这似乎不适用于我的MapReduce结果集,它有多个结果,因为它没有将它们序列化为数组并且错过了逗号,导致无效的json,无论我使用哪种序列化方法。 BsonDocument.ToJson()也为日期写入无效的json。在严格下它写ISODate()并在JavaScript / TenGen下编写newDate()。这两个都导致我的浏览器停止。

所以最后,我不得不求助于建立一个对象图;

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

我浏览了原始的MVC / json.net序列化堆栈;

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