Сериализация сложных классов C# MongoDB
Я работаю с драйвером C# MongoDB, и у меня есть довольно сложная структура JSON для сохранения:
{
"name" : "value",
"age": 1,
"isFemale": true,
"Hobbies" : {
//All data within the "Hobbies" node is dynamic
//and may change from one item to another.
"stringItem" : "value",
"intItem" : 0.0,
"listOfItems" : [
{ "field" : 1696.0 }
],
"intArray" : [ 566.0, 1200.0 ]
},
"Collection" : [
//All data within the "Collection" node is dynamic
//and may change from one item to another.
{
"field" : "string",
"FieldTypeId" : 2.0,
"array" : [
{ "value" : "1024x1000" }
]
}
]
}
У меня есть этот класс, который представляет вышеупомянутый объект:
public class MyClass
{
public string Name;
public int Age;
public bool IsFemale;
public Dictionary<string, object> Hobbies;
public List<Dictionary<string, object>> Collection;
}
Вот что я сохраняю для раздела "хобби":
"Hobbies": {
"stringItem": "value",
"intItem": 1,
"listOfItems": {
"_t": "Newtonsoft.Json.Linq.JArray, Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed",
"_v": [{
"_t": "JObject",
"_v": [{
"_t": "JProperty",
"_v": [{
"_t": "JValue",
"_v": []
}]
},
{
"_t": "JProperty",
"_v": [{
"_t": "JValue",
"_v": []
}]
}]
}]
}
}
Я предполагаю, что мне следует написать пользовательский сериализатор для этого класса, но я не смог найти никакого полезного примера в MONGODB .NET DRIVER Manual
Я попытался запустить и реализовать что-то вроде этого:
public class MyClassSerializer : SerializerBase<MyClass>, IBsonDocumentSerializer
{
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, MyClass value)
{
//What to do here???
base.Serialize(context, args, value);
}
public override MyClass Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
//What to do here???
return base.Deserialize(context, args);
}
public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
{
switch (memberName)
{
case "Name":
serializationInfo = new BsonSerializationInfo(memberName, new StringSerializer(), typeof(string));
return true;
case "Age":
serializationInfo = new BsonSerializationInfo(memberName, new Int16Serializer(), typeof(string));
return true;
case "IsFemale":
serializationInfo = new BsonSerializationInfo(memberName, new BooleanSerializer(), typeof(string));
return true;
case "Hobbies":
serializationInfo = new BsonSerializationInfo(memberName, new TupleSerializer<string, object>(), typeof(string));
return true;
case "Collection":
serializationInfo = new BsonSerializationInfo(memberName, new ArraySerializer<Dictionary<string, object>>(), typeof(string));
return true;
default:
serializationInfo = null;
return false;
}
}
}
Но Я не мог найти ничего общего с этим. Он не полностью реализован, и я прочитал, что мне нужно зарегистрировать сериализатор где-то, но где...?
3 ответов:
Нашел, как сохранить данные в MongoDB здесь: преобразование словаря в BsonDocument, опуская поле _t , и немного расширил его, поэтому я решил поделиться полным решением.
Шаг #1:
В моем классе я объявил 2 члена для каждого значения:
// For the Hobbies object type: [BsonIgnore] //ignore this value in MongoDB public Dictionary<string, object> Hobbies { get; set; } [JsonIgnore] //ignore this value in the response on Get requests [BsonElement(elementName: "Hobbies")] public BsonDocument HobbiesBson { get; set; } /*********************************************************************/ // For the Collection object type: [BsonIgnore] //ignore this value in MongoDB public List<Dictionary<string, object>> Collection { get; set; } [JsonIgnore] //ignore this value in the response on Get requests [BsonElement(elementName: "Collection")] public BsonArray CollectionBson { get; set; }Шаг #2
В моем методе контроллера WebAPI для
Post[HttpPost] public override async Task<IActionResult> Post([FromBody] Person person) { var jsonDoc = JsonConvert.SerializeObject(person.Hobbies); person.HobbiesBson = BsonSerializer.Deserialize<BsonDocument>(jsonDoc); jsonDoc = JsonConvert.SerializeObject(person.Collection); person.CollectionBson = BsonSerializer.Deserialize<BsonArray>(jsonDoc); //save }Шаг #3
В моем запросе
Getя десериализую его обратно следующим образом:[HttpGet("{id?}")] public override async Task<IActionResult> Get(string id = null) { var people = //get data from mongoDB foreach (var person in people) { var bsonDoc = BsonExtensionMethods.ToJson(person.HobbiesBson); person.Hobbies = JsonConvert.DeserializeObject<Dictionary<string, object>>(bsonDoc); bsonDoc = BsonExtensionMethods.ToJson(person.CollectionBson); person.Collection = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(bsonDoc);bsonDoc); } return Ok(people); }Это решило мою вопрос, и я надеюсь, что это может помочь другим, а также : -)
Попробуйте более внимательно прочитать документацию в разделе реестра сериализатора(http://mongodb.github.io/mongo-csharp-driver/2.4/reference/bson/serialization/#serializer-registry):
Реестр сериализаторов содержит все зарегистрированные Ибсонсериализаторы. К нему можно получить доступ через свойство SerializerRegistry статического класса BsonSerializer.
Для регистрации сериализатора используйте либо
BsonSerializer.RegisterSerializer(Type, IBsonSerializer)Или
BsonSerializer.RegisterSerializer<T>(IBsonSerializer<T>)Это добавим их к
BsonSerializer.SerializerRegistryПроверьте API для этих классов здесь - http://mongodb.github.io/mongo-csharp-driver/2.4/apidocs/html/T_MongoDB_Bson_Serialization_BsonSerializer.htm
Простой способ справиться с этой проблемой и не создавать дополнительных свойств, это регистрация пользовательского сериализатора.
комплексный Типизериализатор.КС
namespace MyNamespace.MongoDB.Serializers { public class ComplexTypeSerializer : SerializerBase<object> { public override object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { var serializer = BsonSerializer.LookupSerializer(typeof(BsonDocument)); var document = serializer.Deserialize(context, args); var bsonDocument = document.ToBsonDocument(); var result = BsonExtensionMethods.ToJson(bsonDocument); return JsonConvert.DeserializeObject<IDictionary<string, object>>(result); } public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) { var jsonDocument = JsonConvert.SerializeObject(value); var bsonDocument = BsonSerializer.Deserialize<BsonDocument>(jsonDocument); var serializer = BsonSerializer.LookupSerializer(typeof(BsonDocument)); serializer.Serialize(context, bsonDocument.AsBsonValue); } } }И зарегистрировать его в соответствии с http://mongodb.github.io/mongo-csharp-driver/2.3/reference/bson/serialization/
BsonSerializer.RegisterSerializer(typeof(IDictionary<string, object>), new ComplexTypeSerializer());Или
BsonSerializer.RegisterSerializer(typeof(IList<IDictionary<string, object>>), new ComplexTypeSerializer());Приведенный ниже код был протестирован с простым
IDictionary<string, object>, не уверен, что он будет работать сIList<IDictionary<string, object>>, однако если он не поддерживается, вы можете создать другой пользовательский сериализатор для его поддержки.
Comments