Brian Ogden
Brian Ogden

Reputation: 19212

dotnet publish sometimes copying appsettings.Development.json as appsettings.development.json

In general, the case sensitivity of .NET Core Environment variables has been a nightmare, especially one you start running Docker containers with .NET Core bits and now I find it rearing its ugly head again, here is a dotnet publish output screenshot:

enter image description here

And here is the source code for appsettings files:

enter image description here

Here is the filename in Visual Studio: enter image description here

Using git I can prove the "D" in development is indeed upper case for the Windows filename:

enter image description here

Now this issue has also happened to me with appsettings.Production.json and appsettings.Staging.json. It is intermittent. Sometimes case is respected with dotnet publish copies build artifacts to its publish folder yet other times it lowcases the first letter of the environment for some of my appsettings.json files.

I can delete the publish folder to fix the issue when I developing on my machine but once I go to my Linux build server and the dotnet publish takes place on entirely clean Linux slate, where not publish folder existed before the dotnet publish execution I still get the same issue intermittently.

Also, just wanted to point out that that the .NET Core IHostingEnvironment.IsDevelopment() method is case sensitive, which I cannot believe, but it is so it is more challenging to just setup my code to ignore case, simply because what if another developer trusts IHostingEnvironment.IsDevelopment(), it is a common .NET Core convention:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment() || env.EnvironmentName.ToLower() == "localhost")
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseServiceStack(new AppHost());
}

I could at least do this, to mitigate this case issue:

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

But again referring back to the .NET Core convention, of environment case sensitivity this still leaves a "hole" in the plan do to potential I mentioned above, of a developer using IHostingEnvironment.IsDevelopment()

Upvotes: 3

Views: 2297

Answers (2)

Brian Ogden
Brian Ogden

Reputation: 19212

I wanted to provide the EnvironmentHelper class, I created to assist with this issue across all my APIs, in case anyone else finds it helpful:

public static class EnvironmentHelper
{
    public static bool IsLocalhost(string env)
    {
        return IsEnvironment(env, EnvironmentName.Localhost);
    }

    public static bool IsDevelopment(string env)
    {
        return IsEnvironment(env, EnvironmentName.Development);
    }

    public static bool IsStaging(string env)
    {
        return IsEnvironment(env, EnvironmentName.Staging);
    }

    public static bool IsProduction(string env)
    {
        return IsEnvironment(env, EnvironmentName.Production);
    }

    private static bool IsEnvironment(string env, string environmentName)
    {
        return string.Equals(env, environmentName, StringComparison.CurrentCultureIgnoreCase);
    }
}

public static class EnvironmentName
{
    public static readonly string Localhost = "Localhost";
    public static readonly string Development = "Development";
    public static readonly string Staging = "Staging";
    public static readonly string Production = "Production";
}

Upvotes: -1

Set
Set

Reputation: 49769

IHostingEnvironment.EnvironmentName is just a string property and it has both public getter and setter. You as a developer have full control of what value it contains.And in most real cases it just returns the same value as you have in ASPNETCORE_ENVIRONMENT variable.

Based on HostingEnvironmentExtensions.cs implementation:

  • env.IsDevelopment using the same IHostingEnvironment.EnvironmentName internally to get env name, but yes, compares it with EnvironmentName.Development that contains "Development" as value.

  • In a general way, you may use IHostingEnvironment.IsEnvironment method that gets the expected env name as a second parameter.

As the sample, the following code produces the case-insensitive result:

// IHostingEnvironment env;
env.EnvironmentName = env.EnvironmentName.ToLower();
var result = env.IsEnvironment(EnvironmentName.Development.ToLower());

Regarding files, you may do the following:

  • rename all your config files to lowercase, like appsettings.production.json

  • modify your code to use env name in lower case only:

    .AddJsonFile("appsettings.{env.EnvironmentName.ToLower()}.json")

Upvotes: 2

Related Questions