Написание сериализатора mongo для списка

#c# #mongodb

Вопрос:

Во время выполнения некоторых технических задач и в учебных целях я хотел бы написать свой собственный сериализатор для базы данных mongodb. Насколько я знаю, мне нужно реализовать интерфейс IBsonArraySerializer .

Чтобы иметь небольшой пример, представьте себе следующее poco:

 public class Foo
{
     [BsonSerializer(typeof(MyCustomArraySerializer))]
     public List<Bar> BarList {get; set;}
}

public class Bar 
{
    public string Name {get; set;}
}

public class MyCustomArraySerializer: IBsonArraySerializer //, IBsonDocumentSerializer
{
    public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        throw new NotImplementedException();
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
    {
        throw new NotImplementedException();
    }

    public Type ValueType { get; }
    public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
    {
        throw new NotImplementedException();
    }

    public bool TryGetItemSerializationInfo(out BsonSerializationInfo serializationInfo)
    {
        serializationInfo = null
        return true;
    }
}
 

Как вы можете видеть, это только начало реализации. Проблема в настоящее время заключается в том, что, похоже, сериализатор не используется, если я просто найду в базе данных документ:

Смотрите мою дорожку стека:

     System.NullReferenceException: Object reference not set to an instance of an object.
   at MongoDB.Bson.Serialization.BsonMemberMap.SetSerializer(IBsonSerializer serializer)
   at MongoDB.Bson.Serialization.Attributes.BsonSerializerAttribute.Apply(BsonMemberMap memberMap)
   at MongoDB.Bson.Serialization.Conventions.AttributeConventionPack.AttributeConvention.Apply(BsonMemberMap memberMap)
   at MongoDB.Bson.Serialization.Conventions.ConventionRunner.Apply(BsonClassMap classMap)
   at MongoDB.Bson.Serialization.BsonClassMap.AutoMapClass()
   at MongoDB.Bson.Serialization.BsonClassMap.AutoMap()
   at MongoDB.Bson.Serialization.BsonClassMap.LookupClassMap(Type classType)
   at MongoDB.Bson.Serialization.BsonClassMapSerializationProvider.GetSerializer(Type type, IBsonSerializerRegistry serializerRegistry)
   at MongoDB.Bson.Serialization.BsonSerializerRegistry.CreateSerializer(Type type)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at MongoDB.Bson.Serialization.BsonSerializerRegistry.GetSerializer(Type type)
   at MongoDB.Bson.Serialization.BsonSerializerRegistry.GetSerializer[T]()
   at MongoDB.Driver.MongoCollectionImpl`1..ctor(IMongoDatabase database, CollectionNamespace collectionNamespace, MongoCollectionSettings settings, ICluster cluster, I
OperationExecutor operationExecutor)
   at MongoDB.Driver.MongoDatabaseImpl.GetCollection[TDocument](String name, MongoCollectionSettings settings)
   at Shared.Mongo.MongoService.GetCollection[T](String collectionName) 
 

То, что я ищу, было бы рабочим примером или некоторой помощью, чтобы начать эту работу. Написание сериализатора для одного класса вместо списка с некоторыми классами не было проблемой.

Ответ №1:

как насчет чего-нибудь вроде этого:

 public class MyCustomArraySerializer : SerializerBase<List<Bar>>, IBsonArraySerializer
{
    private static readonly IBsonSerializer<Bar> itemSerializer = BsonSerializer.LookupSerializer<Bar>();

    public override void Serialize(BsonSerializationContext ctx, BsonSerializationArgs args, List<Bar> list)
    {
        ctx.Writer.WriteStartArray();

        if (list is null)
        {
            ctx.Writer.WriteEndArray();
            return;
        }

        foreach (var item in list)
        {
            itemSerializer.Serialize(ctx, item);
        }

        ctx.Writer.WriteEndArray();
    }

    public override List<Bar> Deserialize(BsonDeserializationContext ctx, BsonDeserializationArgs args)
    {
        switch (ctx.Reader.CurrentBsonType)
        {
            case BsonType.Array:
                var list = new List<Bar>();
                ctx.Reader.ReadStartArray();
                while (ctx.Reader.ReadBsonType() != BsonType.EndOfDocument)
                    list.Add(itemSerializer.Deserialize(ctx));
                ctx.Reader.ReadEndArray();
                return list;

            case BsonType.Null:
                ctx.Reader.ReadNull();
                return null;

            default:
                throw new SerializationException("Cannot deserialize!");
        }
    }

    public bool TryGetItemSerializationInfo(out BsonSerializationInfo serializationInfo)
    {
        serializationInfo = new BsonSerializationInfo(null, itemSerializer, itemSerializer.ValueType);
        return true;
    }
}