diff --git a/src/MediatR/Registration/ServiceRegistrar.cs b/src/MediatR/Registration/ServiceRegistrar.cs index 808ee2c4..8016fdb3 100644 --- a/src/MediatR/Registration/ServiceRegistrar.cs +++ b/src/MediatR/Registration/ServiceRegistrar.cs @@ -76,7 +76,7 @@ public static void AddMediatRClasses(IServiceCollection services, MediatRService var arity = multiOpenInterface.GetGenericArguments().Length; var concretions = assembliesToScan - .SelectMany(a => a.DefinedTypes) + .SelectMany(a => a.GetLoadableDefinedTypes()) .Where(type => type.FindInterfacesThatClose(multiOpenInterface).Any()) .Where(type => type.IsConcrete() && type.IsOpenGeneric()) .Where(type => type.GetGenericArguments().Length == arity) @@ -103,7 +103,7 @@ private static void ConnectImplementationsToTypesClosing(Type openRequestInterfa var genericInterfaces = new List(); var types = assembliesToScan - .SelectMany(a => a.DefinedTypes) + .SelectMany(a => a.GetLoadableDefinedTypes()) .Where(t => !t.ContainsGenericParameters || configuration.RegisterGenericHandlers) .Where(t => t.IsConcrete() && t.FindInterfacesThatClose(openRequestInterface).Any()) .Where(configuration.TypeEvaluator) @@ -233,7 +233,7 @@ private static (Type Service, Type Implementation) GetConcreteRegistrationTypes( var typesThatCanCloseForEachParameter = constraintsForEachParameter .Select(constraints => assembliesToScan - .SelectMany(assembly => assembly.GetTypes()) + .SelectMany(assembly => assembly.GetLoadableDefinedTypes()) .Where(type => type.IsClass && !type.IsAbstract && constraints.All(constraint => constraint.IsAssignableFrom(type))).ToList() ).ToList(); @@ -385,6 +385,18 @@ private static void Fill(this IList list, T value) list.Add(value); } + private static IEnumerable GetLoadableDefinedTypes(this Assembly assembly) + { + try + { + return assembly.DefinedTypes; + } + catch (ReflectionTypeLoadException ex) + { + return ex.Types.OfType(); + } + } + private static bool HasNestedGenericResponseType(Type openBehaviorType) { var iface = openBehaviorType.GetInterfaces() @@ -425,7 +437,7 @@ private static void RegisterClosedBehaviorsFromAssemblies( var behaviorParams = openBehaviorType.GetGenericArguments(); var requests = assemblies - .SelectMany(a => a.DefinedTypes) + .SelectMany(a => a.GetLoadableDefinedTypes()) .Where(t => t.IsConcrete() && !t.ContainsGenericParameters) .SelectMany(t => t.GetInterfaces() .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IRequest<>)) diff --git a/test/MediatR.Tests/MicrosoftExtensionsDI/AssemblyResolutionTests.cs b/test/MediatR.Tests/MicrosoftExtensionsDI/AssemblyResolutionTests.cs index b0574276..13e7750e 100644 --- a/test/MediatR.Tests/MicrosoftExtensionsDI/AssemblyResolutionTests.cs +++ b/test/MediatR.Tests/MicrosoftExtensionsDI/AssemblyResolutionTests.cs @@ -3,7 +3,9 @@ namespace MediatR.Extensions.Microsoft.DependencyInjection.Tests; using System; +using System.Collections.Generic; using System.Linq; +using System.Reflection; using Shouldly; using Xunit; @@ -87,4 +89,30 @@ public void ShouldResolveVoidGenericPingRequestHandler() { _provider.GetService>>().ShouldNotBeNull(); } + + [Fact] + public void ShouldNotThrowWhenAssemblyThrowsReflectionTypeLoadException() + { + IServiceCollection services = new ServiceCollection(); + services.AddFakeLogging(); + services.AddSingleton(new Logger()); + + Action registration = () => services.AddMediatR(cfg => + { + cfg.RegisterServicesFromAssemblies(typeof(Ping).Assembly, new BrokenAssembly()); + }); + + registration.ShouldNotThrow(); + + var provider = services.BuildServiceProvider(); + provider.GetService>().ShouldNotBeNull(); + } + + private class BrokenAssembly : Assembly + { + public override IEnumerable DefinedTypes => + throw new ReflectionTypeLoadException( + new Type?[] { typeof(string), null, typeof(int) }, + new Exception?[] { null, new Exception("ByRef-like type cannot be loaded"), null }); + } } \ No newline at end of file