Je suis en train de jouer avec MongoDB et j'ai un objet avec un ObjectId mongodb dessus . Quand je sérialise cela avec la méthode .NET Json (), tout va bien (mais les dates sont horribles!)
Si j'essaie cela avec le sérialiseur JSON.NET, cela me donne une exception InvalidCastException lorsque je tente de sérialiser l'ObjectID
des idées ce qui se passe et comment je peux résoudre ce problème?
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 modifiez la méthode du contrôleur pour utiliser le sérialiseur livré avec .NET, cela fonctionne correctement (mais, celui-ci donne des dates laides, mais bon)
public JsonResult NiceJsonPlease()
{
var q = new TestClass();
q.id = new ObjectId();
q.test = "just updating this";
return Json(q, JsonRequestBehavior.AllowGet);
}
J'avais un pointeur du groupe d'utilisateurs MongoDB ..__ https://groups.google.com/forum/?fromgroups=#!topic/mongodb-csharp/A_DXHuPscnQ
La réponse était .__ "Cela semble être un problème de Json.NET, mais pas vraiment. Il existe ici un type personnalisé qu'il ignore tout simplement. Vous devez dire à Json.NET comment sérialiser un ObjectId."
J'ai donc implémenté la solution suivante
J'ai décoré mon ObjectId avec
[JsonConverter(typeof(ObjectIdConverter))]
Puis écrit un convertisseur personnalisé qui crache simplement la partie Guid de 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;
}
}
Vous pouvez utiliser le type de chaîne .NET au lieu d’ObjectId. Si vous utilisez BsonDateTime, vous aurez le même problème de conversion. Il s'agit d'une classe de domaine 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; }
}
1) Ecrire un convertisseur 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) Enregistrez-le dans JSON.NET globalement avec des paramètres globaux et vous n’avez pas besoin de marquer vos modèles avec de grands attributs.
var _serializerSettings = new JsonSerializerSettings()
{
Converters = new List<JsonConverter> { new ObjectIdConverter() }
};
J'ai résolu un problème similaire que je rencontrais avec l'erreur du sérialiseur JSON.NET/InvalidCastException en définissant le paramètre JsonOutputMode sur strict, ce qui évitait de devoir modifier le type sous-jacent:
var jsonWriterSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };
var json = doc.ToJson(jsonWriterSettings);
Informations supplémentaires disponibles dans l'API: http://api.mongodb.org/csharp/1.8.3/html/d73bf108-d68c-e472-81af-36ac29ea08da.htm
J'ai rencontré un problème similaire avec un projet d'API Web et j'ai fini par me frapper la tête contre le clavier pendant quelques heures avant de trouver ce fil.
Au début, tout fonctionnait bien, mais le problème est survenu après la conversion de mon code pour utiliser ma propre classe personnalisée au lieu de l'objet BsonDocument, comme recommandé dans la documentation du pilote mongoDB C #.
Voici l'équivalent VB.net de 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
J'ai utilisé ce code dans VB.Net et ai travaillé parfaitement, vous pouvez voir le 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