3

我的网络客户端发送 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<> 这很好。

我也试过这些,结果相似;

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。

4

2 回答 2

3

我看不出有什么理由需要为此创建对象模型,除非 MVC3 对您强加该要求。使用 BsonDocument 并直接序列化为 JSON 字符串应该没问题。阅读您的大部分帖子很难,但在调用 MapReduce 的结果归零时,GetResults() 方法返回一个 IEnumerable<BsonDocument> 类型的值,您应该能够轻松地将其转换为 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 序列化程序(如您使用的返回 JsonResult 的 Json 方法)通常会对它们可以序列化和不能序列化的内容施加自己的限制。因此,您遇到的问题似乎与 MongoDB C# 驱动程序无关。

抱歉,我真的不太了解 MVC3 以及它如何将结果转换回 JSON 来说明这一点。

于 2012-04-06T01:11:16.980 回答
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。在 strict 下它写为 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); 
于 2012-04-06T15:22:36.087 回答