JSON.NET erreur de moulage lors de la sérialisation de Mongo ObjectId

je joue avec MongoDB et j'ai un objet avec un objet mongodb dessus. Quand je sérialise ceci avec la méthode .NET Json (), tout est bon (mais les dates sont horribles!)

si j'essaie ceci avec le JSON.NET serialiser il me donne une InvalidCastException en essayant de sérialiser L'ObjectID

des idées sur ce qui se passe et comment je peux arranger ça?

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.

si vous changez la méthode du contrôleur pour utiliser le sérialiseur qui est livré avec .NET, il fonctionne bien (mais, celui-ci donne laid dates, blugh)

public JsonResult NiceJsonPlease()
    {

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

        return Json(q, JsonRequestBehavior.AllowGet);
    }
26
demandé sur Keeno 2013-05-20 18:30:54

6 réponses

Vous pouvez utiliser le type de chaîne de caractères .NET au lieu de ObjectId, vous avez juste besoin de le décorer avec BSON representation. Si vous utilisez BsonDateTime, vous aurez le même problème de conversion. C'est un domaine classe dans mon projet qui utilise ces décorateurs.

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; }
}
42
répondu Andy 2013-05-29 20:17:05

j'avais un pointeur du groupe D'utilisateurs MongoDB. https://groups.google.com/forum/?fromgroups=#!topic/mongodb-csharp/A_DXHuPscnQ

La réponse a été "Cela semble être Json.NET question, mais pas vraiment. Il y a un type personnalisé ici il ne sait tout simplement pas. Tu dois le dire Json.NET comment sérialiser un ObjectId."

ainsi, j'ai implémenté la solution suivante

j'ai décoré mon ObjectId

[JsonConverter(typeof(ObjectIdConverter))]

Ensuite écrit un le convertisseur personnalisé qui crache juste sur la portion Guid de L'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;
    }


}
23
répondu Keeno 2013-05-22 13:45:22

1) Écrire ObjectId convertisseur

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.");
        }
    }
}
            var _serializerSettings = new JsonSerializerSettings()
            {
                Converters = new List<JsonConverter> { new ObjectIdConverter() }
            };
11
répondu ZOXEXIVO 2016-06-22 11:02:16

j'ai résolu un problème similaire, j'ai été rencontré avec le JSON.NET sérialiseur/InvalidCastException erreur en définissant le JsonOutputMode strictes, qui a éliminé la nécessité de changer le type sous-jacent:

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

avec d'autres informations disponibles dans L'API: http://api.mongodb.org/csharp/1.8.3/html/d73bf108-d68c-e472-81af-36ac29ea08da.htm

7
répondu lintunen 2014-01-06 15:14:06

j'ai rencontré un problème similaire avec un projet D'API Web, et j'ai fini par frapper ma tête contre le clavier pendant quelques heures avant de trouver ce fil.

Au début, tout fonctionnait bien, mais ensuite j'ai rencontré le problème après avoir converti mon code pour utiliser ma propre classe personnalisée au lieu de L'objet BsonDocument comme recommandé dans le pilote mongoDB C#. documentation.

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

Ici VB.net équivalent à la solution ci-dessus pour ceux qui en ont besoin;

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
2
répondu Drifter 2014-06-25 19:26:53

j'ai utilisé ce code dans VB.Net et travaillé parfait, vous pouvez voir l'objectId dans la classe et vous pouvez faire la même chose avec le type de données 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
répondu Diego 2017-03-13 18:21:51