我的web客户端发送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。
我看不出有任何理由需要为此创建对象模型,除非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的了解还不够多。
因此,我为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);