autofac / Autofac

An addictive .NET IoC container
https://autofac.org
MIT License
4.44k stars 836 forks source link

ComponentNotRegisteredException thrown when using NUnit Console Runner #1412

Closed marossi7 closed 4 months ago

marossi7 commented 4 months ago

We recently lifted .NET Framework project to .NET 7. All went without major complications, but we encountered an issue when we were trying to execute test cases from a .NET 7 test library which is using NUnit Console 3.16.3 (Release). The test cases use Assembly Scanning method RegisterAssemblyModules(). The interesting fact is that the tests are running fine when ran from Visual Studio, but as longs as we run them from the console runner the following error is encountered.

1) Error : TestRunnerModule.Integration.Tests.ConnectionTestRunnerIntegrationTests.TestRunnerPortTestUpdate_UpdatesWizardData(READyCollector)
Autofac.Core.Registration.ComponentNotRegisteredException : The requested service 'MediatorModule.IMediator' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.

See https://autofac.rtfd.io/help/service-not-registered for more info.
   at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Type serviceType, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
   at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)
   at TestRunnerModule.Integration.Tests.ConnectionTestRunnerIntegrationTests.TestRunnerPortTestUpdate_UpdatesWizardData(DeviceType deviceType) in C:\Users\MHR\source\concentratortool\Tests\DotNet\IntegrationTests\TestRunnerModule.Integration.Tests\ConnectionTestRunnerIntegrationTests.cs:line 241
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)

The Autofac version in the test library is 7.0.1 and we are loading assembly modules using RegisterAssemblyModules().

var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
List<Assembly> allAssemblies = new List<Assembly>();
foreach (string dll in Directory.GetFiles(path, "*MediatorModule.dll"))
{
    allAssemblies.Add(Assembly.LoadFrom(dll));
}
foreach (string dll in Directory.GetFiles(path, "*WizardDataModule.dll"))
{
    allAssemblies.Add(Assembly.LoadFrom(dll));
}

allAssemblies.Add(Assembly.GetExecutingAssembly());

var builder = new ContainerBuilder();
builder.RegisterAssemblyModules(allAssemblies.ToArray());
Container = builder.Build();

When trying to resolve registered assembly / ies (see below) the exception mentioned in the beginning is thrown.

using (var scope = Container.BeginLifetimeScope())
{
    var mediator = scope.Resolve<IMediator>();
    var wizardDataModule = scope.Resolve<IWizardDataModule>();
...

This all worked both in Visual Studio and NUnit Console Runner before the update to .NET 7. The old configuration was .NET Framework 4.7.1 and Autofac 5.1.2.

tillig commented 4 months ago

Logically speaking, if it's working in one environment and not another, that's not so much an Autofac problem than it is an environmental issue. Especially in the case of assembly loading - you'll notice Autofac itself isn't what loads or locates assemblies, Autofac just uses what you give it.

From the above, my guess is that there's an assembly that's being found in Visual Studio but is not being found during console runs.

Be aware that the change from a .NET desktop framework to .NET core, and a pretty big jump at that, is not always just lift-and-shift. Especially when it comes to assembly loading, remoting, AppDomains, and the like - there are differences in how .NET Core works. There's also sometimes differences in how things are working in Visual Studio vs console, like Visual Studio handling things like assembly shadow copies during testing differently than the console runner.

In fact, in .NET Core you generally shouldn't be using a specific NUnit or XUnit console runner, you should be using dotnet test - which may also explain why things aren't working as expected.

Much as we love to help folks, we do have some pretty limited bandwidth to help troubleshoot stuff that can't be clearly linked to an issue in Autofac. This, unfortunately, doesn't fall in that category. If you are able to work out a minimal reproduction that very clearly shows it's an Autofac problem, we'd love to see that (likely in a new issue that explains the actual Autofac challenge).