I've noticed a strange behavior for ASPNETCORE_ENVIRONMENT
- when i set it to
Development
, my application fails (as it should) due to some services' incorrect lifetimes (akacannot consume scoped service...
) - when i set it to
Local
(we useLocal
for local development; we useDevelopment
for the develop env where our frontend works), the application works just fine, no errors are thrown, scoped services are consumed by singleton services...
Is there a way to preserve the behavior of the Development
in the Local
and other environments? The issue is that I was completely unaware that I was pushing invalid code (cross-checking tens of services isn't an easy task - that's why I assumed that it was done by my app locally).
Also - I tried to pin the line where this additional Development
-specific logic is implemented but with no luck. Maybe there's someone here who knows the place - I'd really like to spend a short while reading the code.
I created a minimal reproducible example:
Program.cs
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using WebApplication1;
var builder = Host.CreateDefaultBuilder(args)
.ConfigureHostConfiguration(configHost =>
{
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
builder.Build().Run();
Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using WebApplication1.Services;
namespace WebApplication1
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services
.AddControllers();
services
.AddSingleton<SingletonService>()
.AddScoped<ScopedService>();
}
public void Configure(IApplicationBuilder app)
{
app
.UseRouting();
app.ApplicationServices
.GetService<SingletonService>()
.DoSth();
}
}
}
SingletonService
using System;
namespace WebApplication1.Services;
public class SingletonService
{
private readonly ScopedService _scopedService;
public SingletonService(ScopedService scopedService)
{
_scopedService = scopedService;
}
public void DoSth()
{
Console.WriteLine($"{nameof(SingletonService)} - {nameof(DoSth)}");
_scopedService.DoSth();
}
}
ScopedService.cs
using System;
namespace WebApplication1.Services;
public class ScopedService
{
public void DoSth()
{
Console.WriteLine($"{nameof(ScopedService)} - {nameof(DoSth)}");
}
}
launchSettings.json
{
"profiles": {
"WebApplication1": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "http://localhost:8080",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
CodePudding user response:
When you create the default IHostBuilder
using Host.CreateDefaultBuilder
, it will set service Scope and Building validation to true
when the Environment is "Development". The following is relevant bit of code taken from dotnet's source code:
internal static ServiceProviderOptions CreateDefaultServiceProviderOptions(HostBuilderContext context)
{
bool isDevelopment = context.HostingEnvironment.IsDevelopment();
return new ServiceProviderOptions
{
ValidateScopes = isDevelopment,
ValidateOnBuild = isDevelopment,
};
}
You can navigate the source code starting with Host.CreateDefaultBuilder and ending with HostingHostBuilderExtensions.CreateDefaultServiceProviderOptions.