如何解决MongoDB反序列化'类型没有合适的构造函数或添加方法'错误?



为了快速找到解决方案,我花了一整天的时间浏览了许多stackoverflow/internet博客。

已经发布了类似这个标题的问题,但它们不一样。很明显,我必须自己找到解决办法。把我的发现和方法张贴在这里,这样它可以帮助别人(或我)。我总是忘记我自己的解决方案,很有可能在遥远的将来我又会在这个帖子上结束:))

:得到类似下面

的异常

系统。FormatException HResult=0x80131537 Message=错误在反序列化类的eventstoppublish字段时发生Domain.SeedWork.Aggregate1[[System.String, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]: Type 'DomainManagedList. 1[[Domain.Events.]EventToPublish域,版本=1.0.0.0,文化=中性,PublicKeyToken=null]]'没有合适的构造函数或Add方法。源= MongoDB。Bson
StackTrace: atMongoDB.Bson.Serialization.BsonClassMapSerializer1.DeserializeMemberValue(BsonDeserializationContext context, BsonMemberMap memberMap) at MongoDB.Bson.Serialization.BsonClassMapSerializerDeserializeClass (BsonDeserializationContext上下文)MongoDB.Bson.Serialization.BsonClassMapSerializer1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer序列化器,BsonDeserializationContext上下文)MongoDB.Driver.Core.Operations.CursorBatchDeserializationHelper.DeserializeBatch TDocument (RawBsonArrayIBsonSerializer cc4.1CreateFirstCursorBatch (BsonDocumentcursorDocument)MongoDB.Driver.Core.Operations.FindOperation1.CreateCursor(IChannelSourceHandle channelSource, IChannelHandle channel, BsonDocument commandResult) at MongoDB.Driver.Core.Operations.FindOperation.d__129. movenext ()在MongoDB.Driver.Core.Operations.FindOperation1.<ExecuteAsync>d__128.MoveNext() at MongoDB.Driver.OperationExecutor.<ExecuteReadOperationAsync>d__3. movenext ()在MongoDB.Driver.MongoCollectionImpl1.<ExecuteReadOperationAsync>d__99. movenext ()在MongoDB.Driver.MongoCollectionImpl1.<UsingImplicitSessionAsync>d__107. movenext ()在基础设施。mongodb . repository . mongorepository2.<FindAsync>d__8.MoveNext() in C:devdomain-driven-customer-servicesrcInfrastructureMongoDbRepositoriesMongoRepository.cs:line 65 at Infrastructure.MongoDb.Repositories.Repository2.d__3.MoveNext()在C: 开发 domain-driven-customer-service src 基础设施 MongoDb 库 Repository.cs:行25 .在api . program .d__0. moveext()中C: 开发 Program.cs domain-driven-customer-service src Api:第36行

这个异常最初是在这个调用栈上抛出的:(外部代码)

内部异常1:BsonSerializationException: Type"Domain.Aggregates.DomainManagedList"1 [[Domain.Events.EventToPublish,域,版本=1.0.0.0,文化=中性,PublicKeyToken=null]]'做没有合适的构造函数或Add方法。

对我来说,这个问题的发生是因为我用自定义列表类型DomainManagedList替换了List<T> EventsToPublish { get; set;}中的通用列表类型,CC_11禁止访问可以添加或修改列表中的任何内容的方法(非常像ImmutableList<T>)。"为什么?"这个问题在本文中并不重要,原因很简单,因为我们正在实现领域驱动的设计聚合模式,并且需要具有有限访问权限的领域实体,以便它们只能从聚合本身(而不是从应用层)进行修改。

所以Type没有修复的代码如下所示:

public class DomainManagedList<T> : IEnumerable<T>
{ // Custom type that broke deserialization 
private readonly List<T> _itemList;
public DomainManagedList()
{
_itemList = new List<T>();
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)_itemList).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
internal void Add(T item)
{
_itemList.Add(item);
}
internal void Remove(T item)
{
}
[InvokedOnDeserialization]
// ReSharper disable once UnusedMember.Global | Found via attribute and invoked using reflection
protected DomainManagedList(List<T> itemList)
{
_itemList = itemList;
}
}

注意Add方法具有internal访问修饰符,以防止任何其他程序集的代码更改列表。

考虑到mongoDB驱动程序代码是开源的,我搜索了它的github存储库,发现这个文件https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Bson/Serialization/Serializers/EnumerableInterfaceImplementerSerializer.cs有这个does not have a suitable constructor or Add method行出现在异常中。

所以错误来自EnumerableInterfaceImplementerSerializer类型。在浏览了这个开源MongoDB驱动程序存储库,并在网上搜索了一下如何创建自定义反序列化器后,我得出结论,我需要一个自定义BsonSerializer并覆盖这个反序列化终结器,它应该允许查找非公共方法。基于我们所遵循的编程模型,拥有protected构造函数对我们来说更有意义,这个修复示例展示了这种方法;但是,您可以轻松地调整代码以访问任何其他方法来实现相同的反序列化结果。

修复:我们添加了带有自定义属性的受保护构造函数(其他人不需要),以确定地从自定义Bson序列化器中找到此构造函数。最后确保我们在app start上注册了这个序列化器。完整代码如下:

自定义属性:

[AttributeUsage(AttributeTargets.Constructor)]
public class InvokedOnDeserializationAttribute : Attribute
{
}

自定义类型新定义:(注意:它现在包括受保护的构造函数)

public class DomainManagedList<T> : IEnumerable<T>
{
private readonly List<T> _itemList;
public DomainManagedList()
{
_itemList = new List<T>();
}
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)_itemList).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
internal void Add(T item)
{
_itemList.Add(item);
}
internal void Remove(T item)
{
}
[InvokedOnDeserialization]
// ReSharper disable once UnusedMember.Global | Found via attribute and invoked using reflection
protected DomainManagedList(List<T> itemList)
{
_itemList = itemList;
}
}

定制BsonSerializer:

public class DomainManagedListSerializer<TItem> 
: EnumerableInterfaceImplementerSerializer<DomainManagedList<TItem>, TItem>
{
/// This class has custom deserializer based on suitable constructor.
/// To use this serializer you must register it using following method
/// BsonSerializer.RegisterGenericSerializerDefinition(typeof(DomainManagedList<>), typeof(DomainManagedListSerializer<>));

private readonly ConstructorInfo _constructorInfo;

public DomainManagedListSerializer()
{
_constructorInfo = typeof(DomainManagedList<TItem>)
.GetTypeInfo().GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault(ci => Attribute.IsDefined((MemberInfo) ci, typeof(InvokedOnDeserializationAttribute)));
if (_constructorInfo != null)
{
var constructorParameters = _constructorInfo.GetParameters();
if (constructorParameters.Length == 1)
{
if (constructorParameters[0].ParameterType == typeof(List<TItem>))
{
return;
}
}
}
var message = string.Format("Type '{0}' does not have a suitable constructor that " +
"implements '{1}'.",
typeof(DomainManagedList<TItem>).FullName,
nameof(InvokedOnDeserializationAttribute));
throw new BsonSerializationException(message);
}
protected override DomainManagedList<TItem> FinalizeResult(object accumulator)
{
return (DomainManagedList<TItem>)_constructorInfo.Invoke(new[] { accumulator });
}
}

注册BsonSerializer(与服务注册一起进行):

BsonSerializer.RegisterGenericSerializerDefinition(typeof(DomainManagedList<>), typeof(DomainManagedListSerializer<>));

相关内容

  • 没有找到相关文章

最新更新