You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决MongoDB反序列化‘类型无合适构造函数或Add方法’错误?

解决MongoDB Bson反序列化自定义集合类的异常问题

我花了一整天翻遍Stack Overflow和各类技术博客找解决方案,搜出来的同类问题都和我的情况对不上,只能自己摸索。现在把解决思路和发现分享出来,帮到别人或者以后忘了的自己——毕竟我总记不住自己写的解决方案,指不定哪天又搜到这篇 :)

问题现象

抛出如下异常:

System.FormatException
HResult=0x80131537
消息:反序列化Domain.SeedWork.Aggregate1[[System.String, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]类的EventsToPublish字段时发生错误:类型'DomainManagedList1[[Domain.Events.EventToPublish, Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'没有合适的构造函数或Add方法。
来源:MongoDB.Bson
调用堆栈:
在 MongoDB.Bson.Serialization.BsonClassMapSerializer1.DeserializeMemberValue(BsonDeserializationContext context, BsonMemberMap memberMap) 在 MongoDB.Bson.Serialization.BsonClassMapSerializer1.DeserializeClass(BsonDeserializationContext context)
在 MongoDB.Bson.Serialization.BsonClassMapSerializer1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) 在 MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer1 serializer, BsonDeserializationContext context)
在 MongoDB.Driver.Core.Operations.CursorBatchDeserializationHelper.DeserializeBatch[TDocument](RawBsonArray batch, IBsonSerializer1 documentSerializer, MessageEncoderSettings messageEncoderSettings) 在 MongoDB.Driver.Core.Operations.FindOperation1.CreateFirstCursorBatch(BsonDocument cursorDocument)
在 MongoDB.Driver.Core.Operations.FindOperation1.CreateCursor(IChannelSourceHandle channelSource, IChannelHandle channel, BsonDocument commandResult) 在 MongoDB.Driver.Core.Operations.FindOperation1.d__129.MoveNext()
在 MongoDB.Driver.Core.Operations.FindOperation1.<ExecuteAsync>d__128.MoveNext() 在 MongoDB.Driver.OperationExecutor.<ExecuteReadOperationAsync>d__31.MoveNext()
在 MongoDB.Driver.MongoCollectionImpl1.<ExecuteReadOperationAsync>d__991.MoveNext()
在 MongoDB.Driver.MongoCollectionImpl1.<UsingImplicitSessionAsync>d__1071.MoveNext()
在 Infrastructure.MongoDb.Repositories.MongoRepository2.<FindAsync>d__8.MoveNext() 位置 C:\dev\domain-driven-customer-service\src\Infrastructure\MongoDb\Repositories\MongoRepository.cs:行号 65 在 Infrastructure.MongoDb.Repositories.Repository2.d__3.MoveNext() 位置 C:\dev\domain-driven-customer-service\src\Infrastructure\MongoDb\Repositories\Repository.cs:行号 25
在 Api.Program.d__0.MoveNext() 位置 C:\dev\domain-driven-customer-service\src\Api\Program.cs:行号 36

此异常最初在此调用堆栈中抛出:
[外部代码]

内部异常1: BsonSerializationException: 类型'Domain.Aggregates.DomainManagedList`1[[Domain.Events.EventToPublish, Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'没有合适的构造函数或Add方法。

问题原因

MongoDB的Bson序列化器默认处理集合类型时,会尝试通过无参构造函数创建实例,再调用Add(T item)方法逐个添加元素完成反序列化。而自定义的DomainManagedList<T>类没有满足这两个条件中的任意一个,导致序列化器无法完成反序列化操作。

解决方案

方案一:给自定义集合类添加必要的构造函数和Add方法

直接修改DomainManagedList<T>类,补充无参构造函数和Add方法,让Bson序列化器可以正常识别:

public class DomainManagedList<T> : IEnumerable<T>
{
    private readonly List<T> _internalList = new List<T>();

    // 添加无参构造函数
    public DomainManagedList()
    {
    }

    // 添加支持单个元素的Add方法
    public void Add(T item)
    {
        _internalList.Add(item);
        // 这里可以添加自定义的业务逻辑,比如校验、事件触发等
    }

    // 实现IEnumerable<T>的必要接口方法
    public IEnumerator<T> GetEnumerator()
    {
        return _internalList.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

方案二:注册自定义Bson序列化器

如果不想修改DomainManagedList<T>的代码结构,可以自定义一个序列化器,告诉MongoDB如何处理这个类型:

// 自定义序列化器,继承EnumerableSerializerBase基类
public class DomainManagedListSerializer<T> : EnumerableSerializerBase<DomainManagedList<T>, T>
{
    // 创建自定义集合实例
    protected override DomainManagedList<T> CreateInstance()
    {
        return new DomainManagedList<T>();
    }

    // 定义如何向集合中添加元素
    protected override void AddItem(DomainManagedList<T> instance, T item)
    {
        // 调用自定义集合的添加逻辑,如果有内部方法也可以直接用
        instance.Add(item);
    }
}

// 在MongoDB初始化时注册这个泛型序列化器
BsonSerializer.RegisterGenericSerializerDefinition(
    typeof(DomainManagedList<>), 
    typeof(DomainManagedListSerializer<>)
);

方案三:将自定义集合映射为普通List存储

通过Bson类映射,把DomainManagedList<T>类型的字段序列化为普通List<T>存储到MongoDB,反序列化时再转换回自定义类型:

// 注册Aggregate类的Bson映射规则
BsonClassMap.RegisterClassMap<Aggregate<string>>(cm =>
{
    cm.AutoMap();
    // 把EventsToPublish字段序列化为List<EventToPublish>
    cm.MapMember(a => a.EventsToPublish)
      .SetSerializer(new EnumerableSerializer<List<EventToPublish>, EventToPublish>())
      .SetElementName("EventsToPublish");
    
    // 反序列化完成后,将List转换为自定义的DomainManagedList
    cm.AfterDeserialization(obj =>
    {
        obj.EventsToPublish = new DomainManagedList<EventToPublish>(obj.EventsToPublish.ToList());
    });
});

内容的提问来源于stack exchange,提问作者sbp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 05:05:39