[英]JSON.NET cast error when serializing Mongo ObjectId
我正在玩 MongoDB 并且有一个带有 mongodb ObjectId 的对象。 当我用 .NET Json() 方法序列化它时,一切都很好(但日期太可怕了!)
如果我使用 JSON.NET 序列化程序尝试此操作,它会在尝试序列化 ObjectID 时给我一个 InvalidCastException
有什么想法发生了什么,我该如何解决这个问题?
using MongoDB.Driver;
using MongoDB.Bson;
using Newtonsoft.Json;
//this is a route on a controller
public string NiceJsonPlease()
{
var q = new TestClass();
q.id = new ObjectId();
q.test = "just updating this";
return JsonConvert.SerializeObject(q);
}
//simple test class
class TestClass
{
public ObjectId id; //MongoDB ObjectID
public string test = "hi there";
}
Exception Details: System.InvalidCastException: Specified cast is not valid.
如果您将控制器方法更改为使用 .NET 附带的序列化程序,它可以正常工作(但是,这个日期很丑,blugh)
public JsonResult NiceJsonPlease()
{
var q = new TestClass();
q.id = new ObjectId();
q.test = "just updating this";
return Json(q, JsonRequestBehavior.AllowGet);
}
您可以使用 .NET 字符串类型代替 ObjectId,您只需要使用 BsonRepresentation 对其进行修饰即可。 如果您使用 BsonDateTime,您将遇到相同的转换问题。 这是我的项目中使用这些装饰器的域类。
public class DocumentMetadata
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string Name { get; set; }
public string FullName { get; set; }
[BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
public DateTime DownloadTime { get; set; }
}
我有一个来自 MongoDB 用户组的指针。 https://groups.google.com/forum/?fromgroups=#!topic/mongodb-csharp/A_DXHuPscnQ
回应是
这似乎是一个 Json.NET 问题,但实际上并非如此。 这里有一个自定义类型,它根本不知道。 您需要告诉 Json.NET 如何序列化 ObjectId。
所以,我实施了以下解决方案
我装饰了我的 ObjectId
[JsonConverter(typeof(ObjectIdConverter))]
然后写了一个自定义转换器,它只是吐出 ObjectId 的 Guid 部分
class ObjectIdConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value.ToString());
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
return typeof(ObjectId).IsAssignableFrom(objectType);
//return true;
}
}
1) 编写 ObjectId 转换器
public class ObjectIdConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ObjectId);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType != JsonToken.String)
throw new Exception($"Unexpected token parsing ObjectId. Expected String, got {reader.TokenType}.");
var value = (string)reader.Value;
return string.IsNullOrEmpty(value) ? ObjectId.Empty : new ObjectId(value);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value is ObjectId)
{
var objectId = (ObjectId)value;
writer.WriteValue(objectId != ObjectId.Empty ? objectId.ToString() : string.Empty);
}
else
{
throw new Exception("Expected ObjectId value.");
}
}
}
2) 使用全局设置在 JSON.NET 中全局注册它,你不需要用大属性标记你的模型
var _serializerSettings = new JsonSerializerSettings()
{
Converters = new List<JsonConverter> { new ObjectIdConverter() }
};
3) 重要建议 - 不要在模型中使用 ObjectId - 使用字符串
[BsonRepresentation(BsonType.ObjectId]
public string Id{ get;set; }
我通过将 JsonOutputMode 设置为严格解决了我在 JSON.NET 序列化程序/InvalidCastException 错误中遇到的类似问题,这消除了更改基础类型的需要:
var jsonWriterSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };
var json = doc.ToJson(jsonWriterSettings);
API 中提供了更多信息: http : //api.mongodb.org/csharp/1.8.3/html/d73bf108-d68c-e472-81af-36ac29ea08da.htm
我在一个 Web API 项目中遇到了类似的问题,在我找到这个线程之前,我的头靠在键盘上几个小时。
最初一切正常,但是在将我的代码转换为使用我自己的自定义类而不是 mongoDB C# 驱动程序文档中推荐的 BsonDocument 对象后,我遇到了问题。
这里的 VB.net 相当于上面的解决方案,供需要的人使用;
Public Class DocumentMetadata
<BsonId> _
<BsonRepresentation(BsonType.ObjectId)> _
Public Property Id() As String
Public Property Name() As String
Public Property FullName() As String
<BsonDateTimeOptions(Kind := DateTimeKind.Utc)> _
Public Property DownloadTime() As DateTime
End Class
我在 VB.Net 中使用了这段代码并且工作得很好,你可以在类中看到 objectId,你可以用数据类型 DATE 做同样的事情。
Imports MongoDB.Bson
Imports MongoDB.Bson.Serialization.Attributes
Imports MongoDB.Driver
Public Class _default
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim objMongo As New MongoClient("mongodb://192.168.111.5:27017")
Dim objDatabase As IMongoDatabase = objMongo.GetDatabase("local")
Dim objCollection = objDatabase.GetCollection(Of BsonDocument)("Test")
Dim _ret As New List(Of mongo_users)
Dim result = objCollection.Find(New BsonDocument()).ToList()
Dim _json_response = result.ToJson()
If _json_response <> "" Then
_ret = MongoDB.Bson.Serialization.BsonSerializer.Deserialize(Of List(Of mongo_users))(_json_response)
End If
For Each item In _ret
Response.Write(item.name & " " & item.last_name & "</br>")
Next
End Sub
End Class
Public Class mongo_users
<BsonId>
<BsonRepresentation(BsonType.ObjectId)>
Public Property _id() As String
Public Property status As Integer
Public Property name As String
Public Property last_name As String
Public Property colors As List(Of user_colors)
End Class
Public Class user_colors
Public Property color_name As String
End Class
有没有其他选择
object dotnetObject = BsonTypeMapper.MapToDotNetValue(bsonDocument);
// Json mapped to default .Net objects
string json = Newtonsoft.Json.JsonConvert.SerializeObject(dotnetObject);
// Parsing as JObject
var jobject = JObject.Parse(json);
// Deserializing as your custom Type
var myObject = JsonConvert.DeserializeObject<MyType>(json);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.