Mongo自定义序列化器导致无法创建抽象类

问题描述 投票:0回答:1

Mongo自定义序列化器导致无法创建抽象类

嗨,我正在尝试向我的 mongo 类添加自定义序列化器,但它似乎无法正常工作。 目标是我们的数据库中有古代事件,我想以我们拥有的“新格式”阅读它们。

但是新事件发生了错误。这是结构

public abastract class FooBase
{
    public int Version { get; set; }
    public Guid AggregateId { get; set; }
    //Other properties
    public abstract object GetContent();
}

public class TypedFooBase<T> : FooBase
where T : class
{
    public T TypedContent { get; set; }
    //Other properties
    
    public override object GetContent()
    {
        return TypedContent;
    }
}

然后我创建了一个自定义序列化器,如下所示:

public class BsonAncientEventSerializer<T> : SerializerBase<TypedFooBase<T>> where T : class
{
    public override TypedFooBase<T> Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        var serializer = BsonSerializer.LookupSerializer(typeof(ExpandoObject));
        var obj = serializer.Deserialize(context);
        string valueString = JsonConvert.SerializeObject(obj);
        return JsonConvert.DeserializeObject<TypedFooBase<T>>(valueString, new Json.JsonAncientEventSerializer<T>())
                ?? throw new Exception("something went wrong");
    }

    public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TypedFooBase<T> value)
    {
        var bsonWriter = context.Writer;

        var fields = value.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); 
        var propsAll = value.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); 

        var props = new List<PropertyInfo>(); 
        foreach (var prop in propsAll) 
        { 
            if (prop.CanWrite) 
            { 
                props.Add(prop); 
            } 
        } 

        bsonWriter.WriteStartDocument(); 

        foreach (var field in fields) 
        { 
            bsonWriter.WriteName(field.Name); 
            BsonSerializer.Serialize(bsonWriter, field.FieldType, field.GetValue(value)); 
        } 
        foreach (var prop in props) 
        { 
            bsonWriter.WriteName(prop.Name); 
            BsonSerializer.Serialize(bsonWriter, prop.PropertyType, prop.GetValue(value, null)); 
        } 

         context.Writer.WriteEndDocument(); 
    }
}

然后我注册序列化器:

BsonSerializer.RegisterSerializer(
            typeof(TypedFooBase<TestEvent>),
            new BsonAncientEventSerializer<TestEvent>()
        );

如果我不注册序列化器,一切正常(除了与旧事件的兼容性)。 但是当我添加注册序列化器时,代码无法正常工作;

serialize
工作正常(值正确存储在数据库中);

但是在阅读时,它不起作用。代码根本没有停在

Deserialize

我在代码中访问的集合是一个

IMongoCollection<FooBase>
;

然后,当我执行

collection.Find(...).ToListAsync()
时,它会给我一个
Cannot create an abstract class
的错误。

这是因为它试图将值转换为

FooBase
;

但是它为什么要这么做呢?为什么当我不注册时序列化器工作正常?

谢谢。

c# .net mongodb mongodb-.net-driver
1个回答
1
投票

您看到的行为与您为

TypedFooBase<TestEvent>
注册自定义序列化程序有关,但反序列化期间使用的集合类型是
FooBase
,因此找不到所需的序列化程序。 您可以尝试:

  • 将序列化器映射到基本类型:

      BsonSerializer.RegisterSerializer(
          typeof(FooBase),
          new BsonAncientEventSerializer<TestEvent>()
    

以及适当的序列化器定义:

public class BsonAncientEventSerializer<T> : SerializerBase<FooBase> where T : class
  • 理论上,最好的方法是使用适当的类型来获得结果,例如:

    var result = collection.OfType<TypedFooBase<TestEvent>>().Find("{}").ToList();
    

但要使其工作,您需要实现序列化步骤中跳过的 discriminator 行为,因为

OfType
还添加了序列化文档中未提供的
_t
(鉴别器)过滤器。

  • 另外,你可以看看这个doc

  • 更新:听起来像这样:

    var result = coll.FindSync("{}", new FindOptions<FooBase, TypedFooBase<TestEvent>>()).ToList();
    

也应该有效。

© www.soinside.com 2019 - 2024. All rights reserved.