Сериализация сложных классов 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;
}
}
}


Но Я не мог найти ничего общего с этим. Он не полностью реализован, и я прочитал, что мне нужно зарегистрировать сериализатор где-то, но где...?

947   3  

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

    Ничего не найдено.