Closed Pondidum closed 6 years ago
When you say it fails in Release mode, what is the actual failure?
🤦♂️ I really should have included that!
System.InvalidOperationException : Unable to resolve service for type 'LamarBug.IStorageSession' while attempting to activate 'LamarBug.TogglesController'.
at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
at lambda_method(Closure , IServiceProvider , Object[] )
at Microsoft.AspNetCore.Mvc.Controllers.ControllerActivatorProvider.<>c__DisplayClass4_0.<CreateActivator>b__0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
at Alba.SystemUnderTestExtensions.Scenario(ISystemUnderTest system, Action`1 configure)
at Alba.SystemUnderTestExtensions.Scenario(ISystemUnderTest system, Action`1 configure)
--- End of stack trace from previous location where exception was thrown ---
My initial guess is that it has to do with the scan of TheCallingAssembly
. I would bet that the calling assembly is actually Alba (or maybe XUnit) and not the assembly that contains the actual service registry, so the service registry never actually gets picked up. The thing that makes me scratch my head is: Why does it work in debug mode?
The services.For<>.Use()
syntax will always work because you're directly adding the registration, so that makes sense.
You might be onto something there.
If I change the Startup to explicitly use the RestRegistry
, everything works too:
public void ConfigureContainer(ServiceRegistry services)
{
services.AddMvc();
services.Scan(_ =>
{
_.TheCallingAssembly();
_.WithDefaultConventions();
//_.LookForRegistries();
});
services.IncludeRegistry<RestRegistry>();
}
What I want to do is see the output of .WhatDidIScan()
, but I can't figure out how to get at the container instance in the test 😞
You can do it in the Startup.Configure()
method by casting the app.ApplicationServices
to a Container
. This is what I do in my start up class(es):
if(IsDebugMode)
{
var container = (IContainer)app.ApplicationServices;
Log.Logger.Verbose(container.WhatDidIScan());
Log.Logger.Verbose(container.WhatDoIHave());
}
Well that is a helpful snippet even if we don't figure this out! Anyway the output of WhatDidIScan()
shows the difference between Debug and Release:
Debug:
2018-10-22 21:17:54 [Verbose] All Scanners
================================================================
Assemblies
----------
* LamarBug, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Conventions
--------
* Default I[Name]/[Name] registration convention
* Lamar.Scanning.Conventions.FindRegistriesScanner
Assemblies
----------
* LamarBug, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Conventions
--------
* Default I[Name]/[Name] registration convention
No problems were encountered in exporting types from Assemblies
And Release
2018-10-22 21:17:02 [Verbose] All Scanners
================================================================
Assemblies
----------
* Microsoft.AspNetCore.Hosting, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
Conventions
--------
* Default I[Name]/[Name] registration convention
* Lamar.Scanning.Conventions.FindRegistriesScanner
No problems were encountered in exporting types from Assemblies
The remaining question I guess is...why the initial scan only finds the Microsoft.AspNetCore.Hosting
in Release, but my actual assembly in Debug?
For the record, I am not certain if this is a bug in Alba or Lamar.
Given all the information we have, I would venture to guess this has something to do with the way Alba is running the tests in the different configurations. As I said, the _.TheCallingAssembly()
is only going to check the assembly which is actually executing the code.
So you can work around this, for both modes by adding into your scan: _..AssemblyContainingType<Startup>();
. This will force it to scan the assembly which contains your StartupClass
. Alternatively, if your registries are in a different assembly, then you can simply use one of your registry types as the generic argument.
There are a bunch of other methods on the scanner that you can use to add different assemblies to the scanning if neither of those is perfectly suitable, but the bottom line is that you have to make sure you are scanning all the right assemblies.
Yes, I am aware of how the scanning works, so have updated my test to get around this. I've "moved" this issue to the Alba repo as that seems to be the more likely cuplrit, so will shut this issue.
Thanks for your help in diagnosing!
For the record, I am not certain if this is a bug in Alba or Lamar.
The problem occurs when an object is registered outside the
Startup
class in Alba, using.ConfigureServices
, and aServiceRegistry
within the application makes use of that registered type to register another type. This works fine when run inDebug
mode, but underRelease
, the second type registration is not found. Probably better explained with a test...ServiceRegistries
, and make theservices.For...
call inConfigureContainer
, it works in both Release and DebugPackage versions used:
I can upload the test project if that would help.