Skip to content

Instantly share code, notes, and snippets.

@lurumad
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lurumad/410e05154cc7e9f2f3eb to your computer and use it in GitHub Desktop.
Save lurumad/410e05154cc7e9f2f3eb to your computer and use it in GitHub Desktop.
MongoCSharpDriver deserialize anonymous type
public class TempDataDocument
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
[BsonElement("key")]
public string Key { get; set; }
[BsonElement("value")]
[BsonSerializer(typeof(CustomSerializer))]
public object Value { get; set; }
}
public class CustomSerializer : IBsonSerializer
{
#region Implementation of IBsonSerializer
public object Deserialize(MongoDB.Bson.IO.BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options)
{
return Deserialize(bsonReader, nominalType, null, options);
}
public object Deserialize(
MongoDB.Bson.IO.BsonReader bsonReader,
Type nominalType,
Type actualType,
IBsonSerializationOptions options)
{
if (bsonReader.GetCurrentBsonType() != BsonType.Document)
{
throw new Exception("Not document");
}
var bsonDocument = BsonSerializer.Deserialize(bsonReader, typeof(BsonDocument), options) as BsonDocument;
var cleanJson = Regex.Replace(bsonDocument.ToJson(), @"ObjectId\((.[a-f0-9]{24}.)\)", (m) => m.Groups[1].Value);
return JsonConvert.DeserializeObject<object>(cleanJson);
}
public IBsonSerializationOptions GetDefaultSerializationOptions()
{
return new DocumentSerializationOptions();
}
public void Serialize(MongoDB.Bson.IO.BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
{
var json = (value == null) ? "{}": JsonConvert.SerializeObject(value);
BsonDocument document = BsonDocument.Parse(json);
BsonSerializer.Serialize(bsonWriter, typeof(BsonDocument), document,options);
}
#endregion
}
void Main()
{
var client = new MongoClient("mongodb://localhost:27017");
var server = client.GetServer();
var database = server.GetDatabase("mvc");
var collection = database.GetCollection("tempdata");
var document = new TempDataDocument()
{
Key = "key1",
Value = new
{
Nombre = "Sergio",
Twitter = "@panicoenlaxbox"
}
};
collection.Insert(document);
var data = collection.FindAs<TempDataDocument>(Query.EQ("key", "key1"));
Console.WriteLine(data);
}
@panicoenlaxbox
Copy link

Hola Luis,

Que conste que soy un completo beginner con MongoDB, pero creo que el problema está cuando intentas deserializar sin un tipo destino, luego debería deserializar a un tipo anónimo, pero parece que no está soportado. En tu caso, no hay problema, porque lo que está guardado e intentas deserializar encaja perfectamente en el tipo destino. De hecho, el problema no está en guardar (MongoDB parece tragarse todo), el problema está al deserializar.

He creado este otro gist para que veas el error "in situ" https://gist.github.com/panicoenlaxbox/5c6784e2be1171eed003

En el caso del proveedor de TempData fíjate que yo puedo guardar cualquier cosa y podría no tener siempre un tipo destino válido para deserializar. Es por ello que intento atajar el problema antes de que ocurra, por eso no dejo guardar tipos anónimos (que insisto no habría problema, el problema sería después al intentar deserializarlos).

En el caso de la implementación de TempData basada en cookies no hay ningún problema porque serializa/deserializa Json.NET que sí sabe trabajar con tipos anónimos.

@lurumad
Copy link
Author

lurumad commented May 20, 2014

Lo he actualizado ;)

@panicoenlaxbox
Copy link

Gran trabajo, probado y funcionando!!

De todas formas, tengo alguna duda (seguro fruto de mi inexperiencia con MongoDB) He visto en http://docs.mongodb.org/ecosystem/tutorial/serialize-documents-with-the-csharp-driver/#write-a-custom-serializer que supuestamente lo único que hay que hacer es implementar IBsonSerializer, a excepción de este párrafo que podemos obviarlo porque no nos gusta LINQ sobre MongoDB :) "However, there are some extension interfaces that will enable further use in other parts of the api such as saving a class or LINQ"

Para mí algo falla porque no es verdad que sólo haya que hacer eso, por ejemplo con tu código todo funciona a la primera, pero fíjate en que no se está grabando el campo _id en la base de datos. De esta forma, si ejecutas el código una segunda vez te lanza el siguiente error "An unhandled exception of type 'MongoDB.Driver.MongoDuplicateKeyException' occurred in MongoDB.Driver.dll" y yo me pregunto: Si sólo estás decorando la propiedad Value (no la clase entera) ¿Por qué no se graba el _id?

Luego investigaré más en casa, gracias por preocuparte por esto, actualizaré el post seguro luego con todo lo que saquemos, de hecho yo lo estoy utilizando en producción así que estoy muy interesado :)

@lurumad
Copy link
Author

lurumad commented May 20, 2014

Yo si que tengo el Id:

/* 0 */
{
"_id" : ObjectId("537b23be3814fe25e8119e01"),
"key" : "key1",
"value" : {
"Nombre" : "Sergio",
"Twitter" : "@panicoenlaxbox"
}
}

/* 1 */
{
"_id" : ObjectId("537b4e733814fe181cd96417"),
"key" : "key1",
"value" : {
"Nombre" : "Sergio",
"Twitter" : "@panicoenlaxbox"
}
}

/* 2 */
{
"_id" : ObjectId("537b4e753814fe181cd96418"),
"key" : "key1",
"value" : {
"Nombre" : "Sergio",
"Twitter" : "@panicoenlaxbox"
}
}

Y no me salta ninguna excepción :(

@panicoenlaxbox
Copy link

Pues llevas razón, error mío, luego actualizo el post con una super-mención para un tal lurumad :)
Gracias

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment