runtime: Services resolving incorrectly in Development environment but not Production
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
For an IEnumerable<> of services resolved using GetServices, we found that the list of services returned is different when using --environment=Development versus any other values including blank.
We have two service implementations defined. When in Production, service A and B are in the enumerable. In development, service A is in the list twice, without B.
Expected Behavior
Should always resolve service A and B regardless of the enviroment.
Steps To Reproduce
Given types:
public interface IMarker { }
public interface IBaseService<T> { }
public class BaseService : IBaseService<A> { }
public class GenericService<T> : IBaseService<T>
where T : IMarker
{
}
public class A : IMarker { }
This test passes (I use Shouldly for assertions, sorry):
[Fact]
public void Should_resolve_correctly_directly()
{
var services = new ServiceCollection();
services.AddTransient<IBaseService<A>, BaseService>();
services.AddTransient(typeof(IBaseService<>), typeof(GenericService<>));
var serviceProvider = services.BuildServiceProvider();
var handlers = serviceProvider
.GetServices<IBaseService<A>>()
.ToList();
handlers.Count.ShouldBe(2);
var handlersTypes = handlers
.Select(h => h.GetType())
.ToList();
handlersTypes.ShouldContain(typeof(BaseService));
handlersTypes.ShouldContain(typeof(GenericService<A>));
}
This test passes using the WebApplication.CreateBuilder method:
[Fact]
public void Should_resolve_correctly_with_no_env_set()
{
var builder = WebApplication.CreateBuilder();
builder.Services.AddTransient<IBaseService<A>, BaseService>();
builder.Services.AddTransient(typeof(IBaseService<>), typeof(GenericService<>));
var serviceProvider = builder.Services.BuildServiceProvider();
var handlers = serviceProvider
.GetServices<IBaseService<A>>()
.ToList();
handlers.Count.ShouldBe(2);
var handlersTypes = handlers
.Select(h => h.GetType())
.ToList();
handlersTypes.ShouldContain(typeof(BaseService));
handlersTypes.ShouldContain(typeof(GenericService<A>));
var app = builder.Build();
var appHandlers = app.Services
.GetServices<IBaseService<A>>()
.ToList();
appHandlers.Count.ShouldBe(2);
var appHandlersTypes = appHandlers
.Select(h => h.GetType())
.ToList();
appHandlersTypes.ShouldContain(typeof(BaseService));
appHandlersTypes.ShouldContain(typeof(GenericService<A>));
}
This test fails:
[Fact]
public void Should_resolve_correctly_in_development()
{
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
EnvironmentName = Environments.Development
});
builder.Services.AddTransient<IBaseService<A>, BaseService>();
builder.Services.AddTransient(typeof(IBaseService<>), typeof(GenericService<>));
var serviceProvider = builder.Services.BuildServiceProvider();
var handlers = serviceProvider
.GetServices<IBaseService<A>>()
.ToList();
handlers.Count.ShouldBe(2);
var handlersTypes = handlers
.Select(h => h.GetType())
.ToList();
handlersTypes.ShouldContain(typeof(BaseService));
handlersTypes.ShouldContain(typeof(GenericService<A>));
var app = builder.Build();
var appHandlers = app.Services
.GetServices<IBaseService<A>>()
.ToList();
appHandlers.Count.ShouldBe(2);
var appHandlersTypes = appHandlers
.Select(h => h.GetType())
.ToList();
appHandlersTypes.ShouldContain(typeof(BaseService));
appHandlersTypes.ShouldContain(typeof(GenericService<A>));
}
The first set of assertions succeeds when I build the service provider directly from builder.Services. Once I call builder.Build and use the app.Services to resolve, it gives me the incorrect set of results. Whether or not I build the service provider does not change the second assertion.
Exceptions (if any)
No response
.NET Version
6.0.101
Anything else?
No response
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 12
- Comments: 15 (13 by maintainers)
.NET 7.0 is done. This issue is planned for .NET 8.0 now.
Setting
EnvironmentName = Environments.DevelopmentcausesValidateOnBuild = trueto be set on the ServiceContainer. Here’s a reduced repro without web components: