37

我正在玩 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 附带的序列化程序,它可以正常工作(但是,这个给出了丑陋的日期,布鲁格)

public JsonResult NiceJsonPlease()
    {

        var q = new TestClass();
        q.id = new ObjectId();
        q.test = "just updating this";

        return Json(q, JsonRequestBehavior.AllowGet);
    }
4

7 回答 7

60

您可以使用 .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; }
}
于 2013-05-29T20:17:05.200 回答
29

我有一个来自 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;
    }


}
于 2013-05-22T13:45:22.037 回答
20

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; }
于 2016-06-22T11:02:16.020 回答
10

我通过将 JsonOutputMode 设置为 strict 解决了我在 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

于 2014-01-06T15:14:06.677 回答
2

我在一个 Web API 项目中遇到了类似的问题,在我找到这个线程之前,我在键盘上敲了几个小时。

最初一切正常,但是在将我的代码转换为使用我自己的自定义类而不是 mongoDB C# 驱动程序文档中推荐的 BsonDocument 对象后,我遇到了问题。

http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-csharp-driver/#bsondocument-object-model-vs-your-own-domain-classes

对于那些需要它的人来说,这里的 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
于 2014-06-25T19:26:53.180 回答
1

还有另一种选择

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);
于 2021-05-10T14:24:35.390 回答
0

我在 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
于 2017-03-13T18:21:51.727 回答