C# 与Autofac并行运行xUnit集成测试时,无法加载Castle.Proxies.IReadinessProxy类型

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

我有一个问题,我已经很多天无法解决。 我将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);