1

I'm developing a .NET Core (.NET 6) WPF app, and I have a problem detecting the dev environment (Development or Production).

I'm creating a IHost when my WPF app starts, in order to use Dependency Injection and all the other .NET Core goodies, like this:

public partial class App : Application
{
    private readonly IHost host;

    public App()
    {
        host = Host.CreateDefaultBuilder()
            .UseContentRoot(CoreConstants.MaintenanceToolBinFolder)
            .ConfigureServices((context, services) =>
            {
                var configuration = context.Configuration;
                //...
            })
            .Build();
    }
}

Now, in an ASP.net Core web app this would automatically read the ASPNETCORE_ENVIRONMENT environmental variable and use it to determine the current environment. However, this is completely ignored here, and the environment is always "Production".

What is the proper way to detect the environment in this case? Should I just manually read the variable and set the environment, or is there a more "proper" way?

Master_T
  • 7,232
  • 11
  • 72
  • 144
  • Are you always running in debug mode within visual studio whilst in development. – Andy Jan 24 '23 at 13:41
  • The usual way to do this in a desktop app is to deliver different config, which is covered in the link above. I doubt it's changed but the config over-ride like you get in asp.net was not included in desktop build tooling. You can also detect if the debugger is attached and consider that to be development. – Andy Jan 24 '23 at 13:52
  • @Andy: thanks for your link, I will keep it in mind in the future, although for this particular question I've accepted Guru's answer since it fits the question better and mirrors the way it is done in ASP.net exactly. – Master_T Jan 24 '23 at 14:23

2 Answers2

3

I just did my very first "ASP-like" WPF app and it works like a charm.

Here is my code, with Dependency Injection and Serilog logger configuration as bonus:

public partial class App : Application
{
    private IHost? _host;

    protected override void OnStartup(StartupEventArgs e)
    {
        Startup? startup = null;
        this._host = Host.CreateDefaultBuilder(e.Args)
            .ConfigureHostConfiguration(config =>
            {
                config.AddEnvironmentVariables(prefix: "APP_");
            })
            .ConfigureAppConfiguration((hostingContext, configBuilder) =>
            {
                configBuilder.Sources.Clear();

                IHostEnvironment env = hostingContext.HostingEnvironment;

                configBuilder
                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false)
                    ;

                if (env.IsDevelopment())
                {
                    configBuilder.AddUserSecrets(Assembly.GetExecutingAssembly());
                }

                IConfiguration configuration = configBuilder.Build();

                Log.Logger = new LoggerConfiguration()
                    .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
                    .Enrich.FromLogContext()
                    .ReadFrom.Configuration(configuration)
                    .CreateLogger();

                Log.Information("*** Starting application ***");
            })
            .ConfigureServices((_, services) =>
            {
                services.AddSingleton< ... >();
                    ...
            })
            .UseSerilog()
            .Build()
            ;

        IServiceProvider sp = this._host.Services;

        var window = sp.GetRequiredService<MainWindow>();
        window.Show();
    }

    protected override void OnExit(ExitEventArgs e)
    {
        base.OnExit(e);
        this._host?.Dispose();
    }
}

Also remember to configure the launch settings in the Project Property window or directly in the launchSettings.json file:

{
  "profiles": {
    "<app name>": {
      "commandName": "Project",
      "environmentVariables": {
        "APP_ENVIRONMENT": "Development"
      }
    }
  }
}

Note: I'm using .NET 7.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
Mario Vernari
  • 6,649
  • 1
  • 32
  • 44
  • +1 because your code made me understand how to customize this in the future, the call to `.ConfigureHostConfiguration(builder => builder.AddEnvironmentVariables(prefix: "XXX_"))` is the key, with this I can make it read the ASPNETCORE_ENVIRONMENT variable or any other if I want, it works perfectly! However, apparently there is a default for this that doesn't require customization (see the accepted answer) – Master_T Jan 24 '23 at 14:16
  • What Serilog package are you using for the UseSerilog() extension method? Thanks. EDIT: Serilog.Extensions.Hosting – ken2k Jan 31 '23 at 14:39
1

Since you are using generic host (Host.CreateDefaultBuilder()) you should be able to use DOTNET_ENVIRONMENT variable. From docs:

  • Loads host configuration from:
    • Environment variables prefixed with DOTNET_.
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • This is indeed the solution I was looking for, as it is the most similar to the one adopted for ASP.net apps. – Master_T Jan 24 '23 at 14:20
  • 1
    @Master_T ASP.NET Core actually should use `DOTNET_ENVIRONMENT` if `ASPNETCORE_ENVIRONMENT` is not set, AFAIK =) – Guru Stron Jan 24 '23 at 18:04