dotnet publish 有时会将 appsettings.Development.json 复制为 appsettings.development.json

Posted

技术标签:

【中文标题】dotnet publish 有时会将 appsettings.Development.json 复制为 appsettings.development.json【英文标题】:dotnet publish sometimes copying appsettings.Development.json as appsettings.development.json 【发布时间】:2017-10-02 17:56:49 【问题描述】:

一般来说,.NET Core 环境变量的大小写敏感性一直是一场噩梦,尤其是当你开始使用 .NET Core 位运行 Docker 容器时,现在我发现它又抬起了丑陋的脑袋,这是一个 dotnet 发布输出截图:

这里是 appsettings 文件的源代码:

这是 Visual Studio 中的文件名:

使用 git 我可以证明开发中的“D”确实是 Windows 文件名的大写:

现在这个问题也发生在我的 appsettings.Production.json 和 appsettings.Staging.json 中。它是间歇性的。有时,dotnet publish 会尊重大小写,将构建工件复制到其发布文件夹,但有时它会将我的一些 appsettings.json 文件的环境首字母小写。

当我在我的机器上开发时,我可以删除发布文件夹来解决问题,但是一旦我进入我的 Linux 构建服务器并且 dotnet 发布发生在完全干净的 Linux 平板上,在 dotnet 发布执行之前不存在发布文件夹我仍然间歇性地遇到同样的问题。

另外,只是想指出 .NET Core IHostingEnvironment.IsDevelopment() 方法是区分大小写的,我不敢相信,但是将我的代码设置为忽略大小写更具挑战性,因为如果另一个开发者信任 IHostingEnvironment.IsDevelopment(),这是一个常见的 .NET Core 约定:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

    if (env.IsDevelopment() || env.EnvironmentName.ToLower() == "localhost")
    
        app.UseDeveloperExceptionPage();
    

    app.UseServiceStack(new AppHost());

我至少可以这样做,以缓解这个案例问题:

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);

但再次参考 .NET Core 约定,环境大小写敏感性这仍然在我上面提到的开发人员使用IHostingEnvironment.IsDevelopment() 的计划中留下了一个“漏洞”

【问题讨论】:

【参考方案1】:

IHostingEnvironment.EnvironmentName 只是一个字符串属性,它同时具有公共 getter 和 setter。作为开发人员,您可以完全控制它包含的值。在大多数实际情况下,它只返回与 ASPNETCORE_ENVIRONMENT 变量中相同的值。

基于HostingEnvironmentExtensions.cs 实现:

env.IsDevelopment 在内部使用相同的IHostingEnvironment.EnvironmentName 来获取环境名称,但是是的,将其与包含“开发”作为值的EnvironmentName.Development 进行比较。

一般来说,您可以使用IHostingEnvironment.IsEnvironment 方法获取预期的环境名称作为第二个参数。

作为示例,以下代码产生不区分大小写的结果:

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

关于文件,您可以执行以下操作:

将所有配置文件重命名为小写,例如appsettings.production.json

修改您的代码以仅使用小写的环境名称:

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

【讨论】:

是的,解决了部分问题,不过我最近刚刚添加到我的问题中,在我看到你回答之前,IHostingEnvironment.IsDevelopment() 仍然存在漏洞,阅读底部的更新我的问题是关于你的答案的一次捕获【参考方案2】:

我想提供 EnvironmentHelper 类,我创建该类是为了在我的所有 API 中帮助解决这个问题,以防其他人发现它有帮助:

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";

【讨论】:

以上是关于dotnet publish 有时会将 appsettings.Development.json 复制为 appsettings.development.json的主要内容,如果未能解决你的问题,请参考以下文章

如何覆盖 dotnet publish 的目标文件夹

dotnet publish 在预发布完成之前运行

使用 dotnet publish 发布多个 web.config

“dotnet publish”命令行跳过部署到 Azure Functions

在 asp.net 核心的构建后事件中运行 dotnet publish

Mac 上的“dotnet publish”创建一个 .dll,但在 Linux 上生成一个可执行文件?