3

I have stumbled across a strange situation for an ASP.NET Core 3.1 application: environmentVariables defined in launchSettings.json are not set (e.g. Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") is null).

The launchsettings.json looks like this:

{
  "iisSettings": {
    "windowsAuthentication": true,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:60907",
      "sslPort": 44364
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger/index.html",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "MyApp.WebApi": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "swagger/index.html",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "https://localhost:5001;http://localhost:5000"
    }
  }
}

and I am using IIS Express.

Things I have investigated or tried:

  1. Pulled the project on another machine and it works as expected: Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT" is "Development".

  2. Ran a very similar project (virtually the same configuration) on the same machine and it works as expected

  3. Removed all launchsettings.json content except for IIS Express and it still has the same issue

  4. Launched using another profile and it works as expected

  5. Closed Visual Studio -> removed .vs folder -> reopened VS + rerun project. The issue persists

  6. Restarted the machine, the problem persists

  7. Added other environment variables in the profile and they are also ignored

  8. Compared the working projects vs. the non-working project IISExpress applicationhost.config files and did not notice any difference (except for the project paths).

The only workaround I have right now is to make a local change in Program.cs and make sure I never commit it, but I am looking for a real fix:

string originalEnv = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", originalEnv ?? "Development");

I have run out of ideas to try. I assume it is something related to an IIS Express configuration on that particular machine for this particular application, but I could not find anything related to environment variables in %userprofile%\My Documents\IISExpress\config\applicationhost.config

Alexei - check Codidact
  • 22,016
  • 16
  • 145
  • 164

2 Answers2

7

You're confusing your OS's environment variables with the .NET Core runtime environment. They've got the same name, and one can get promoted to the other, but they're not the same.

The environment variables in launchSettings.json ("runtime environment" or "host configuration values") do not get promoted to actual environment variables of the OS, the latter which you can read through Environment.GetEnvironmentVariable().

You can read the application's ASPNETCORE_ENVIRONMENT through IHostingEnvironment.Environment or IWebHostEnvironment.EnvironmentName.

To recap: you should not use Environment.GetEnvironmentVariable() to read the ASPNETCORE_ENVIRONMENT from the OS's environment variables, because the .NET Core environment can be set in different ways.

It's the other way around: during the host initialization, the ASPNETCORE_ENVIRONMENT environment variable is read from the operating system, but this value can be provided in different ways, namely through the launchSettings.json, .vscode/launch.json or one can even use AddCommandLine(args), and then:

dotnet run --environment "Staging"

And your Environment.GetEnvironmentVariable() will report the wrong value, if any.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • Thanks for the complete explanation. I will fix the code to use `IWebHostEnvironment` (`IHostingEnvironment` seems to be obsolete). However, now I am puzzled about why it works in some cases (e.g. the same project on another machine, or another project on the same machine). – Alexei - check Codidact Jan 05 '21 at 13:17
  • Because that other machine may have the Windows environment variable set, for example by another developer. – CodeCaster Jan 05 '21 at 13:30
  • Well, another project on the same machine works. Also checked the system / user environment variables and ASPNETCORE_ENVIRONMENT is not set. Very strange. I need this to check in Program.cs and [this answer](https://stackoverflow.com/a/62787375/2780791) suggests that what I am trying works. However, I will have to use the method from [this answer](https://stackoverflow.com/a/51195701/2780791) instead. – Alexei - check Codidact Jan 06 '21 at 11:35
  • `hostingEnv.EnvironmentName` reports `Production` instead of `Development`, so there is something fishy related to reading launchsettings. – Alexei - check Codidact Jan 06 '21 at 11:42
  • Okay, that's weird. Can't really dive into it now. – CodeCaster Jan 06 '21 at 12:47
  • What a footgun! In the universe of coding, platforms, operating systems the phrase "Environment Variables" has a single, distinct meaning. I suppose we are SOL if using launchSettings.json files with legacy MVC5 / .NET 4.8 projects! – nicholas May 27 '21 at 18:12
4

To add on @CodeCaster answer why you can't actually retrieve it and what happens behind the scenes. Yes you can use IWebHostEnvironment to retrieve what you need but the enviroment name IS NOT an enviroment variable that asp.net core sets it is something it simply reads from if you dont have it in your lauchsettings.json

There are 3 stages of enviroment:

  • Machine
  • User
  • Process

Now the difference here is that Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") looks always at the process level it does not look at the OS level. You can of course change that by using GetEnvironmentVariable(String, EnvironmentVariableTarget) but that wont help you as @CodeCaster mentioned. So use the IWebHostEnvironment to get the enviroment name should be sufficient for your case but you may have set the DOTNET_ENVIROMENT in machine level or something so make sure to know what you specifically need.

But how can IWebHostEnviroment retrieve it?

Its because those "enviroment names" are not enviroment variables. ASP.Net Core does set any kind of enviroment variable. It insteads defines it as a way for you to say ok this is a development enviroment and this is a production one. It can read from the Machine or User Enviroment variables but it does not create any varaibles of some sort.

So the reason why you cant read those enviroment variables while using IIS is because those enviroment variables dont exist in the first place.

Also furthermore the IWebHostEnvironment does not somehow magically read the enviroment variables. They simply load it from the lauchsettings.json so again there is no enviroment variable setting.

More specifically in the source code:

            hostingEnvironment.EnvironmentName =
            options.Environment ??
            hostingEnvironment.EnvironmentName;

It is either retrieved by the options you have defined and if you have not defined it then it will stay the same.

Furthermore process enviroment variables do not persist after terminating the process so there is no need for machine restart or clean up of those variables. (General comment)

A_kat
  • 1,459
  • 10
  • 17