Lamar interaction differs between Debug and Release mode
Pondidum opened this issue · 2 comments
This issue "moved" from the Lamar repo to here as it seems more likely this is a problem in Alba (or Xunit, I suppose.)
The problem occurs when an object is registered outside the Startup
class in Alba, using .ConfigureServices
, and a ServiceRegistry
within the application makes use of that registered type to register another type. This works fine when running in Debug
mode, but under Release
, the second type registration is not found. Probably better explained with a test...
- If you run this in Debug mode, the test passes, however, if run in Release, it fails.
- If you remove the use of
ServiceRegistries
, and make theservices.For...
call inConfigureContainer
, it works in both Release and Debug WhatDidIScan
indicates that in Debug mode the root assembly is my testapp (LamarBug
), but under Release isMicrosoft.AspNetCore.Hosting
(full output at the bottom of this issue)- If I use the Registry directly (
services.IncludeRegistry<RestRegistry>();
) the test passes
I have a workaround in place, so this isn't drastically urgent, but just caused a lot of head-scratching when I found it.
Package versions used:
<PackageReference Include="Alba.AspNetCore2" Version="1.4.3" />
<PackageReference Include="Lamar" Version="1.1.2" />
<PackageReference Include="Lamar.Microsoft.DependencyInjection" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
I can upload the test project if that would help.
[Fact]
public Task<IScenarioResult> Test1()
{
var storage = new InMemoryStorage();
var system = SystemUnderTest.ForStartup<Startup>();
system.Configure(builder => builder.UseLamar());
system.ConfigureServices(services =>
{
services.AddSingleton<IStorage>(storage);
});
return system.Scenario(_ =>
{
_.Get.Url("/Toggles");
_.StatusCodeShouldBe(HttpStatusCode.OK);
_.ContentShouldBe("{\"message\":\"LamarBug.InMemorySession\"}");
});
}
public interface IStorage
{
IStorageSession CreateSession();
}
public interface IStorageSession
{
}
public class InMemoryStorage : IStorage
{
public IStorageSession CreateSession() => new InMemorySession();
}
public class InMemorySession : IStorageSession
{
}
public class Startup
{
public void ConfigureContainer(ServiceRegistry services)
{
services.AddMvc();
services.Scan(_ =>
{
_.TheCallingAssembly();
_.WithDefaultConventions();
_.LookForRegistries();
});
//services.For<IStorageSession>().Use(c => c.GetInstance<IStorage>().CreateSession()).Scoped();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseMvc();
}
}
[Route("Toggles")]
public class TogglesController : Controller
{
private readonly IStorageSession _session;
public TogglesController(IStorageSession session)
{
_session = session;
}
[Route("")]
[HttpGet]
public async Task<IActionResult> Get()
{
return new JsonResult(new { Message = _session.GetType().ToString() });
}
}
public class RestRegistry : ServiceRegistry
{
public RestRegistry()
{
Scan(a =>
{
a.TheCallingAssembly();
a.WithDefaultConventions();
});
For<IStorageSession>().Use(c => c.GetInstance<IStorage>().CreateSession()).Scoped();
}
}
Stack Trace:
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 ---
Output of WhatDidIScan()
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
@Pondidum I'm going to lazily claim that this goes away with Alba 2 because it stops doing anything special for ASP.Net Core bootstrapping. Sorry for the very, very slow response here:/
@jeremydmiller I'd forgotten about it to be honest - I used a workaround in the end anyway!