Home > Enterprise >  ASP.NET Core 3.1 - `Development` value for ASPNETCORE_ENVIRONMENT triggers additional services'
ASP.NET Core 3.1 - `Development` value for ASPNETCORE_ENVIRONMENT triggers additional services'

Time:06-21

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 (aka cannot consume scoped service...)
  • when i set it to Local (we use Local for local development; we use Development 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.

  • Related