C# 与Autofac并行运行xUnit集成测试时,无法加载Castle.Proxies.IReadinessProxy类型
我有一个问题,我已经很多天无法解决。 我将xUnit与给定的then-when抽象结合使用,以使测试更具可读性 我正在EventStore上使用包装器并运行一些集成测试。他们都很顺利。。除了一个在并行运行时失败和xUnit并行运行,但是如果我按顺序运行它们,它们都会成功 我无法理解为什么这会成为一个问题,因为每一个事实都应该在给定的时间运行构造函数和测试函数。在每一个事实中,我都实例化了一个Autofac ContainerBuilder,构建了容器并解析了它的IComponentContext,所以在理论上,每个测试都应该是预期的等分和幂等的 这是我一直收到的例外情况:C# 与Autofac并行运行xUnit集成测试时,无法加载Castle.Proxies.IReadinessProxy类型,c#,autofac,xunit,castle-dynamicproxy,eventstoredb,C#,Autofac,Xunit,Castle Dynamicproxy,Eventstoredb,我有一个问题,我已经很多天无法解决。 我将xUnit与给定的then-when抽象结合使用,以使测试更具可读性 我正在EventStore上使用包装器并运行一些集成测试。他们都很顺利。。除了一个在并行运行时失败和xUnit并行运行,但是如果我按顺序运行它们,它们都会成功 我无法理解为什么这会成为一个问题,因为每一个事实都应该在给定的时间运行构造函数和测试函数。在每一个事实中,我都实例化了一个Autofac ContainerBuilder,构建了容器并解析了它的IComponentContext
Autofac.Core.DependencyResolutionException : An exception was thrown while activating SalesOrder.EventStore.Infra.EventStore.EventStore -> SalesOrder.EventStore.Infra.EventStore.DomainEventsRetriever -> SalesOrder.EventStore.Infra.EventStore.Factories.DomainEventFactory -> λ:SalesOrder.EventStore.Infra.EventStore.EventTypeResolver.
---- System.Reflection.ReflectionTypeLoadException : Unable to load one or more of the requested types.
Could not load type 'Castle.Proxies.IReadinessProxy' from assembly 'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters, Object& decoratorTarget) in C:\projects\autofac\src\Autofac\Core\Resolving\InstanceLookup.cs:line 136
at Autofac.Core.Resolving.InstanceLookup.Execute() in C:\projects\autofac\src\Autofac\Core\Resolving\InstanceLookup.cs:line 85
at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\Core\Resolving\ResolveOperation.cs:line 130
at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\Core\Resolving\ResolveOperation.cs:line 83
at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance) in C:\projects\autofac\src\Autofac\ResolutionExtensions.cs:line 1041
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\ResolutionExtensions.cs:line 871
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\ResolutionExtensions.cs:line 300
at SalesOrder.EventStore.Infra.EventStore.Autofac.IntegrationTests.EventStoreExtensionsTests.ResolveTests.Given_A_Container_With_Event_Store_Registered_When_Resolving_An_IEventStore.When() in C:\src\SalesOrder.EventStore\SalesOrder.EventStore.Infra.EventStore.Autofac.IntegrationTests\EventStoreExtensionsTests\ResolveTests.cs:line 53
at SalesOrder.EventStore.Infra.EventStore.Autofac.IntegrationTests.EventStoreExtensionsTests.ResolveTests.Given_A_Container_With_Event_Store_Registered_When_Resolving_An_IEventStore..ctor()
----- Inner Stack Trace -----
at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
at System.Reflection.RuntimeModule.GetTypes()
at System.Reflection.Assembly.GetTypes()
at SalesOrder.EventStore.Infra.EventStore.Autofac.EventStoreExtensions.<>c.<RegisterResolvers>b__6_2(Assembly s) in C:\src\SalesOrder.EventStore\SalesOrder.EventStore.Infra.EventStore.Autofac\EventStoreExtensions.cs:line 174
at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()
at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
at System.Collections.Generic.List`1.AddEnumerable(IEnumerable`1 enumerable)
at SalesOrder.EventStore.Infra.EventStore.Factories.EventTypeResolverFactory.Create(IEnumerable`1 existingTypes, IReadOnlyDictionary`2 domainEventSerializerDeserializers) in C:\src\SalesOrder.EventStore\SalesOrder.EventStore.Infra.EventStore\Factories\EventTypeResolverFactory.cs:line 16
at SalesOrder.EventStore.Infra.EventStore.Autofac.EventStoreExtensions.<>c__DisplayClass6_0.<RegisterResolvers>b__1(IComponentContext context) in C:\src\SalesOrder.EventStore\SalesOrder.EventStore.Infra.EventStore.Autofac\EventStoreExtensions.cs:line 180
at Autofac.Builder.RegistrationBuilder.<>c__DisplayClass0_0`1.<ForDelegate>b__0(IComponentContext c, IEnumerable`1 p) in C:\projects\autofac\src\Autofac\Builder\RegistrationBuilder.cs:line 62
at Autofac.Core.Activators.Delegate.DelegateActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\Core\Activators\Delegate\DelegateActivator.cs:line 71
at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters, Object& decoratorTarget) in C:\projects\autofac\src\Autofac\Core\Resolving\InstanceLookup.cs:line 118
更新2:这是我在实现和所有测试中使用的IoCC Autofac注册方法。这有点复杂,因为我使用反射来保持EventStore包装完全通用,但只是为了防止有人看到可能会影响测试的怪异内容
public static class EventStoreExtensions
{
public static void RegisterEventStore(
this ContainerBuilder builder,
Func<IComponentContext, EventStoreOptions> optionsRetriever,
Func<IComponentContext, ReadinessOptions> readinessOptionsRetriever,
Func<IComponentContext, CustomDomainEventMappersOptions> customDomainEventMappersOptionsRetriever = null)
{
RegisterEventStoreConnection(builder, optionsRetriever);
RegisterFactories(builder);
RegisterEventStoreManager(builder);
RegisterConverters(builder);
RegisterResolvers(builder, customDomainEventMappersOptionsRetriever);
RegisterEventStoreServices(builder);
RegisterEventStoreReadinessCheck(builder, readinessOptionsRetriever);
}
private static void RegisterEventStoreReadinessCheck(
ContainerBuilder builder,
Func<IComponentContext, ReadinessOptions> readinessOptionsRetriever)
{
builder
.Register(context =>
{
var ctx = context.Resolve<IComponentContext>();
var readinessOptions = readinessOptionsRetriever.Invoke(ctx);
var timeout = readinessOptions.Timeout;
var eventStoreConnection = context.Resolve<IEventStoreConnection>();
var eventStoreReadiness =
new EventStoreReadiness(
eventStoreConnection,
timeout);
return eventStoreReadiness;
})
.As<IEventStoreReadiness>()
.As<IReadiness>()
.SingleInstance();
}
private static void RegisterEventStoreConnection(
ContainerBuilder builder,
Func<IComponentContext, EventStoreOptions> optionsRetriever)
{
builder
.Register(context =>
{
var ctx = context.Resolve<IComponentContext>();
var eventStoreOptions = optionsRetriever.Invoke(ctx);
ConnectionSettings connectionSetting =
ConnectionSettings
.Create()
.KeepReconnecting();
var urlString = eventStoreOptions.Url;
var port = eventStoreOptions.Port;
var ipAddress = IPAddress.Parse(urlString);
var tcpEndPoint = new IPEndPoint(ipAddress, port);
var eventStoreConnection = EventStoreConnection.Create(connectionSetting, tcpEndPoint);
return eventStoreConnection;
})
.As<IEventStoreConnection>()
.SingleInstance();
}
private static void RegisterFactories(
ContainerBuilder builder)
{
builder
.RegisterType<DomainEventFactory>()
.As<IDomainEventFactory>()
.SingleInstance();
builder
.RegisterType<EventDataFactory>()
.As<IEventDataFactory>()
.SingleInstance();
builder
.RegisterType<ExpectedVersionFactory>()
.As<IExpectedVersionFactory>()
.SingleInstance();
builder
.RegisterType<IdFactory>()
.As<IIdFactory>()
.SingleInstance();
builder
.RegisterType<StreamNameFactory>()
.As<IStreamNameFactory>()
.SingleInstance();
builder
.RegisterType<RetrievedEventFactory>()
.As<IRetrievedEventFactory>()
.SingleInstance();
}
private static void RegisterEventStoreManager(ContainerBuilder builder)
{
builder
.RegisterType<EventStoreManager>()
.As<IEventStoreManager>()
.SingleInstance();
}
private static void RegisterConverters(ContainerBuilder builder)
{
builder
.Register(context =>
{
var utf8Encoding = new BytesConverter(Encoding.UTF8);
return utf8Encoding;
})
.As<IBytesConverter>()
.SingleInstance();
builder
.RegisterType<NewtonsoftConverter>()
.As<IJsonConverter>()
.SingleInstance();
}
private static void RegisterResolvers(
ContainerBuilder builder,
Func<IComponentContext, CustomDomainEventMappersOptions> customDomainEventMappersOptionsRetriever)
{
builder
.Register(context =>
{
var ctx = context.Resolve<IComponentContext>();
var customDomainEventMappersOptions = customDomainEventMappersOptionsRetriever?.Invoke(ctx);
var domainEventSerializerDeserializers =
customDomainEventMappersOptions?.DomainEventSerializerDeserializers;
var mapperResolver = MapperResolverFactory.Create(domainEventSerializerDeserializers);
return mapperResolver;
})
.As<IMapperResolver>()
.SingleInstance();
builder
.Register(context =>
{
var ctx = context.Resolve<IComponentContext>();
var assembliesLoaded = AppDomain.CurrentDomain.GetAssemblies();
var domainEventTypes =
assembliesLoaded
.SelectMany(s => s.GetTypes())
.Where(x => typeof(IDomainEvent).IsAssignableFrom(x)
&& x.IsClass);
var customDomainEventMappersOptions = customDomainEventMappersOptionsRetriever?.Invoke(ctx);
var domainEventSerializerDeserializers =
customDomainEventMappersOptions?.DomainEventSerializerDeserializers;
var typeResolver =
EventTypeResolverFactory.Create(
domainEventTypes,
domainEventSerializerDeserializers);
return typeResolver;
})
.As<IEventTypeResolver>()
.SingleInstance();
}
private static void RegisterEventStoreServices(ContainerBuilder builder)
{
builder
.RegisterType<EventStoreRepository>()
.As<IEventStoreRepository>();
builder
.RegisterType<DomainEventsPersister>()
.As<IDomainEventsPersister>();
builder
.RegisterType<DomainEventsRetriever>()
.As<IDomainEventsRetriever>();
builder
.RegisterType<EventStore>()
.As<IEventStore>();
}
}
更新3:这是一个完整的存储库,以防有人觉得无聊,想要复制它。它是一个通用的事件存储包装器,用于使用官方C驱动程序为Greg Young的事件存储产品实现的事件源
有趣的是,这个问题似乎每隔一段时间就会消失。事实上,重启电脑后,所有测试通常都能正常通过。其他时候,情况并非如此,因此我怀疑这与我在运行时加载程序集时出现问题有关:内部验证指示无法加载类型 无法从程序集“DynamicProxyGenAssembly2,版本=0.0.0.0,区域性=中性,PublicKeyToken=null”加载类型“Castle.Proxies.IReadinessProxy” 它来自这一行:
at System.Reflection.Assembly.GetTypes()
at SalesOrder.EventStore.Infra.EventStore.Autofac.EventStoreExtensions.<>c <RegisterResolvers>b__6_2(Assembly s) in C:\src\SalesOrder.EventStore\SalesOrder.EventStore.Infra.EventStore.Autofac\EventStoreExtensions.cs:line 174
at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()
at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
这意味着其中一个程序集包含一个类型,该类型包含对未加载的另一个程序集的引用。根据出错类型的名称,它似乎与castle自动生成的类型相关
您可以订阅静态AppDomain.CurrentDomain.AssemblyResolve和AppDomain.CurrentDomain.TypeResolve事件,以更好地了解未加载程序集的原因,也可以手动加载。有关更多信息,请参阅
在某些情况下,异常是正常的,可以使用如下代码忽略:
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly)
{
// TODO: Argument validation
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
return e.Types.Where(t => t != null);
}
}
内部exeption表示无法加载类型 无法从程序集“DynamicProxyGenAssembly2,版本=0.0.0.0,区域性=中性,PublicKeyToken=null”加载类型“Castle.Proxies.IReadinessProxy” 它来自这一行:
at System.Reflection.Assembly.GetTypes()
at SalesOrder.EventStore.Infra.EventStore.Autofac.EventStoreExtensions.<>c <RegisterResolvers>b__6_2(Assembly s) in C:\src\SalesOrder.EventStore\SalesOrder.EventStore.Infra.EventStore.Autofac\EventStoreExtensions.cs:line 174
at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()
at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
这意味着其中一个程序集包含一个类型,该类型包含对未加载的另一个程序集的引用。根据出错类型的名称,它似乎与castle自动生成的类型相关
您可以订阅静态AppDomain.CurrentDomain.AssemblyResolve和AppDomain.CurrentDomain.TypeResolve事件,以更好地了解未加载程序集的原因,也可以手动加载。有关更多信息,请参阅
在某些情况下,异常是正常的,可以使用如下代码忽略:
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly)
{
// TODO: Argument validation
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
return e.Types.Where(t => t != null);
}
}
DynamicProxy Assembly2是由使用CastleProxy的模拟系统构建的临时部件。NSSubstitute和Moq存在一些类似的公开问题,表明问题是Castle.Core甚至.Net Framework中的竞争条件。有关更多详细信息,请参见:DynamicProxy Assembly2是由使用CastleProxy的模拟系统生成的临时程序集。NSSubstitute和Moq存在一些类似的公开问题,表明问题是Castle.Core甚至.Net Framework中的竞争条件。请参阅:有关更多详细信息,请确保在单元测试项目中为这些COM依赖项将嵌入互操作类型设置为“否”。默认情况下,此属性设置为“是”。当您从这些COM对象在单元测试中模拟对象时,不应嵌入它们
如果您有COM依赖项,请确保在这些COM依赖项的单元测试项目中将“嵌入互操作类型”设置为“否”。默认情况下,此属性设置为“是”。当您从这些COM对象在单元测试中模拟对象时,不应嵌入它们
我试着用第三个参数调用RegisterEventStore,如果可选参数导致反射出现问题,那么这个参数是可选的,但是也没有帮助。你呢?仅用于解决方案跟踪:您是否在某处使用castle dynamic proxy?不是同一个人。Moq或Autofac或..必须在内部使用动态代理。。我不是直接使用它,虽然Moq确实使用DynamicProxy,但在您的代码中,或者在异常堆栈跟踪中,都没有表明这里涉及Moq。在我看来,你更可能使用一些未命名的Autof
与DynamicProxy集成的ac扩展。我已尝试使用第三个参数调用RegisterEventStore,如果可选参数导致反射出现问题,则该参数是可选的,但这也没有帮助。你呢?仅用于解决方案跟踪:您是否在某处使用castle dynamic proxy?不是同一个人。Moq或Autofac或..必须在内部使用动态代理。。我不是直接使用它,虽然Moq确实使用DynamicProxy,但在您的代码中,或者在异常堆栈跟踪中,都没有表明这里涉及Moq。在我看来,您更可能正在使用与DynamicProxy集成的未命名Autofac扩展。我稍后会尝试。所以你认为这与加载程序集的速度有关,而不是与我在autofac中注册的方式有关?如前所述,它仅在并行运行所有测试时发生。感谢与Autofac相关的任何事情。例外情况来自GetTypes方法。我猜您的appdomain中有缺少程序集的程序集。缺少的一个似乎与Castle.Core动态代理有关。您可以使用AssemblyResolve和TypeResolve AppDomain.Current events查找更多信息。我稍后再试。所以你认为这与加载程序集的速度有关,而不是与我在autofac中注册的方式有关?如前所述,它仅在并行运行所有测试时发生。感谢与Autofac相关的任何事情。例外情况来自GetTypes方法。我猜您的appdomain中有缺少程序集的程序集。缺少的一个似乎与Castle.Core动态代理有关。您可以使用AssemblyResolve和TypeResolve AppDomain.Current events查找更多信息。
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly)
{
// TODO: Argument validation
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e)
{
return e.Types.Where(t => t != null);
}
}
var domainEventTypes = assembliesLoaded
.SelectMany(s => s.GetLoadableTypes())
.Where(x => typeof(IDomainEvent).IsAssignableFrom(x)
&& x.IsClass);