JSON.NET cast error when serializing Mongo ObjectId

后端 未结 6 1238
旧巷少年郎
旧巷少年郎 2020-11-28 09:36

I am playing around with MongoDB and have an object with a mongodb ObjectId on it. When I serialise this with the .NET Json() method, all is good (but the dates are horrible

相关标签:
6条回答
  • 2020-11-28 09:43

    You can use .NET string type instead of ObjectId, You just need to decorate it with BsonRepresentation. If you use BsonDateTime, you will have the same conversion issue. This is a domain class in my project that uses those decorators.

    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; }
    }
    
    0 讨论(0)
  • 2020-11-28 09:47

    I had a pointer from the MongoDB user group. https://groups.google.com/forum/?fromgroups=#!topic/mongodb-csharp/A_DXHuPscnQ

    The response was "This seems to be a Json.NET issue, but not really. There is a custom type here it simply doesn't know about. You need to tell Json.NET how to serialize an ObjectId."

    So, I implemented the following solution

    I decorated my ObjectId with

    [JsonConverter(typeof(ObjectIdConverter))]
    

    Then wrote a custom converter that just spits out the Guid portion of the ObjectId

     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;
        }
    
    
    }
    
    0 讨论(0)
  • 2020-11-28 09:48

    1) Write ObjectId converter

    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) Register it in JSON.NET globally with global settings and you not need mark you models with big attributes

                var _serializerSettings = new JsonSerializerSettings()
                {
                    Converters = new List<JsonConverter> { new ObjectIdConverter() }
                };
    

    3) Big advice - don't use ObjectId in your models - use string

    [BsonRepresentation(BsonType.ObjectId]
    public string Id{ get;set; }
    
    0 讨论(0)
  • 2020-11-28 09:53

    I ran into a similar problem with a Web API project, and wound up beating my head against the keyboard for a few hours before I found this thread.

    Initially everything was working fine, but then I ran into the problem after converting my code to use my own custom class instead of the BsonDocument object as recommended in the mongoDB C# driver documentation.

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

    Here the VB.net equivalent to the solution above for those that need it;

    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
    
    0 讨论(0)
  • I used this code in VB.Net and worked perfect, you can see the objectId in the class and you can do the same thing with the data type 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
    
    0 讨论(0)
  • 2020-11-28 09:58

    I resolved a similar problem I was experiencing with the JSON.NET serializer/InvalidCastException error by setting the JsonOutputMode to strict, which eradicated the need to change the underlying type:

    var jsonWriterSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };
    var json = doc.ToJson(jsonWriterSettings);
    

    With further information available in the API: http://api.mongodb.org/csharp/1.8.3/html/d73bf108-d68c-e472-81af-36ac29ea08da.htm

    0 讨论(0)
提交回复
热议问题