Aspnetcore: 在 VS 中为 AspNetCore 项目启用 web.config 转换

创建于 2017-05-01  ·  91评论  ·  资料来源: dotnet/aspnetcore

让我先说我不喜欢 web.config,但是将 AspNetCore 应用程序发布到 IIS 的经验真的很差。

AspNetCore 的配置系统围绕 ASPNETCORE_ENVIRONMENT 变量展开,基于该变量可以加载和应用不同的配置。

为特定部署设置这个变量是一场噩梦,似乎有很多关于如何去做的困惑:

问题的症结似乎可以归结为两个问题:

1) VS 中的 ASP.NET Core 项目不支持我们所知道的 web.config 转换
2) 改变 ASPNETCORE_ENVIRONMENT 唯一合理的方法是使用 web.config

设置全局 ASPNETCORE_ENVIRONMENT 不是一个选项,因为它会为单个服务器上的每个站点设置它。 web.config 曾经是自包含的配置。 在 IIS 用例中,这种对全局 env 变量的依赖是不好的。

总而言之,我相信 IIS 发布故事应该引起关注,因为许多像我这样正在过渡到 AspNetCore 的开发人员希望使用他们现有的基础设施进行部署并逐步进行。 目前这个故事过于复杂且不完整。

我需要 web.config 转换的另一个例子: https :

最有用的评论

完全同意第一个帖子。 它的设计非常灵活,但最终证明它很难自动化。 例如,我有一个应用程序,我将其发布到另一台服务器上的 IIS。 它也在本地 IIS 上运行(通过文件夹发布)。 所以我在 web.config 中设置了开发环境。 但随后我需要在发布期间将其更改为 Production 或其他任何内容。 我猜很常见的任务。 我相信这是不可能的,对吧? 我必须在远程服务器上手动编辑 web.config。

理想情况下,应通过“dotnet publish”支持设置环境(对于任何发布目标):

dotnet publish ... -environment=Production

dotnet publish可以搜索web.%Enviroment%.config (Web.Production.config, Web.Development.config) 文件并将其与 web.config 合并(转换)。 最后,我们将获得正确的 ASPNETCORE_ENVIRONMENT 值:

    <environmentVariables>
        <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="value passed to publish" />
    </environmentVariables>         

所有91条评论

FWIW,我同意。 我们只需要明确它是用于 IIS 设置的。 另一件事是我们已经不再使用模板中的默认web.config ,因此需要弄清楚这一点。

/cc @sayedihashimi

不过,这仅适用于 IIS 吗? 我认为问题的关键是使用 ASPNETCORE_ENVIRONMENT 变量 fullstop 让网站知道它处于哪个环境中。

我认为一个非常常见的场景是将各种登台/QA 环境托管在同一个 IIS 实例中的同一个盒子上。 可能有 3 个团队都有自己的“环境”,他们可以部署到这些“环境”来测试他们的代码(比如部署一个特定的分支),但他们都使用同一个盒子。

如果我们采用一些示例代码来说明 appsettings.json 如何在每个环境中切换:

public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); Configuration = builder.Build(); }
上面的场景是行不通的,因为环境变量是系统范围的。 它可能是位于它前面的 IIS、nginx 等,并且配置交换将不起作用。

大多数时候我看到了上面的内容,建议使用 Docker,或者使用类似 Puppet/Chef 的东西来管理应用程序配置,所以没有 appsettings.{env}.json,但我认为这使得路径从完整框架 MVC 就难多了。

@mindingdata您实际上可以控制确定Program.cs环境来自何处的逻辑。 环境变量只是一种声明方式(主要方式)。 如果您想根据某个魔术文件或一天中的时间做其他事情,请在UseEnvironment(environmentName)上调用WebHostBuidler

澄清一下,这绝对仅适用于 IIS 配置。 当前用于应用程序设置的 JSON 配置系统非常好,我完全推荐它。

更进一步:我发现当我使用 web.config 尝试覆盖系统环境设置时,它根本不起作用。 当我的系统环境设置设置为“开发”并且我尝试使用 web.config(如下所示)将其设置为“生产”时,应用程序仍然认为它正在开发中运行。 (在 IIS 中运行的 ASP.NET Core 应用程序)。

<environmentVariables>
      <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
</environmentVariables>

我认为这是正确的地方。 我构建了一个 N 层演示,但似乎无法弄清楚如何将 IHostingEnvironment 注入到我的数据访问层项目中。 该项目是我访问我的数据库的地方,我获得到该层的连接字符串的唯一方法是使用配置文件的魔术字符串覆盖 OnConfiguring 方法。

我还研究了慢速猎豹,但这似乎是围绕“调试、发布”或“开发、生产”的当前方法进行的,具体取决于您使用的是 VS 方法还是环境变量。

一定有我遗漏的信息。 MS 不能希望每个人都构建单层应用程序。

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
           var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json");

            var config = builder.Build();
            var connstr = config.GetConnectionString("connStr");            
            optionsBuilder.UseSqlServer(connstr);
        }

那么这方面有任何进展吗?

我们应该能够在应用程序的配置中设置 env,而无需求助于魔法

是的,我也想在这方面取得一些进展。 目前不知道我应该如何使用不同的环境变量将单独的项目发布到同一个盒子。

我最终想出了一个相当简单的解决方案。 在主 appsettings.json 文件中,我指定了我想要的环境:

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "ActiveEnvironment": "Development"
}

在 Program.CS 中,我然后构建一个 IConfiguration,并在加载环境特定的配置文件之前将环境名称设置为“ActiveEnvironment”的值。

public static void Main(string[] args)
{
    WebHost.CreateDefaultBuilder()
    .ConfigureAppConfiguration((hostingContext, config) =>
    {
        // Get the environment from our hostContext.
        var env = hostingContext.HostingEnvironment;
        config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

        // Build an initial configuration.
        IConfiguration Configuration = config.Build();

        // Set the environment name.
        env.EnvironmentName = Configuration.GetSection("ActiveEnvironment").Value;

        // Load the configuration file for our specific environment.
        config.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: false, reloadOnChange: true)
        .AddEnvironmentVariables();
    })
    .UseStartup<Startup>()
    .Build()
    .Run();
}

显然,当发布到不同的环境时,'ActiveEnvironment' 需要相应地改变。

@DaleMckeown我打算做类似的事情,但我对你的实现有疑问。 我看到您正在使用 Microsoft.AspNetCore.WebHost 创建默认配置。 这种方法是否仍然适用于没有 Web 组件的控制台应用程序?

@Swazimodo我还没有在控制台应用程序的上下文中尝试过这个解决方案,所以我不确定。 最好打赌看看是否有其他方法可以为控制台应用程序设置环境变量。

我们以不同的方式处理这件事。 我们设置我们的构建代理
环境特定的设置文件并覆盖根设置文件
用它。 我们的构建为我们创建的每个环境制作了一个单独的 zip 文件
部署到。

2017 年 10 月 26 日星期四下午 12:48,Dale Mckeown通知@ github.com
写道:

@Swazimodo https://github.com/swazimodo我还没试过这个解决方案
在控制台应用程序的上下文中,所以我不确定。 最好的赌注
看看是否有另一种方法来设置环境变量
控制台应用程序。


您收到此消息是因为您订阅了此线程。
直接回复本邮件,在GitHub上查看
https://github.com/aspnet/Home/issues/2019#issuecomment-339728441或静音
线程
https://github.com/notifications/unsubscribe-auth/AAx4bT20JSb0XSzNBIAiiubq9mTVKbW5ks5swLf6gaJpZM4NMx25
.

似乎所有解决方案都需要某种后期构建/发布调整? 我最终在应用程序根目录中删除了一个空文本文件并将其作为环境传递。 我错过了什么吗?

完全同意第一个帖子。 它的设计非常灵活,但最终证明它很难自动化。 例如,我有一个应用程序,我将其发布到另一台服务器上的 IIS。 它也在本地 IIS 上运行(通过文件夹发布)。 所以我在 web.config 中设置了开发环境。 但随后我需要在发布期间将其更改为 Production 或其他任何内容。 我猜很常见的任务。 我相信这是不可能的,对吧? 我必须在远程服务器上手动编辑 web.config。

理想情况下,应通过“dotnet publish”支持设置环境(对于任何发布目标):

dotnet publish ... -environment=Production

dotnet publish可以搜索web.%Enviroment%.config (Web.Production.config, Web.Development.config) 文件并将其与 web.config 合并(转换)。 最后,我们将获得正确的 ASPNETCORE_ENVIRONMENT 值:

    <environmentVariables>
        <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="value passed to publish" />
    </environmentVariables>         

@evil-shrike 查看https://github.com/nil4/dotnet-transform-xdt以了解构建/发布时间配置转换。

也许是一个用例。 我需要将日志写入 .\App_Data 因为我的应用程序运行器对 .\App_Data 下的所有内容具有读/写访问权限,但只能读取 .\ 下的所有其他内容。 我使用 web 部署,并希望能够使用 App_Data 下的日志文件夹部署像这样的 web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
    </handlers>
    <aspNetCore processPath=".\<assembly>.exe" stdoutLogEnabled="true" stdoutLogFile=".\App_Data\logs\stdout" />
  </system.webServer>
</configuration>

您可能会问,为什么不将这些设置放在 web.config 文件中而不是 web.release.config 中呢? 好吧,当我在本地针对 IIS Express 进行开发时, processPath=".\<executable>.exe"不是可执行文件所在的位置。 所以我得到了很好的“HTTP 错误 502.5 - 进程失败”错误。

我们使用 Jenkins 自动化我们的构建,我们现有的在 NetFramework 项目中按环境进行 vars 配置的方法是通过 web.config 转换。 所以我们认为我们也可以在 dotnet 中做到这一点。

事实证明, msbuild仍然与 aspnet core csproj 兼容,用于进行 web.config 转换!

我们可以在 Asp.Net Core csproj 中添加TransformXml发布任务:

<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v15.0\Web\Microsoft.Web.Publishing.Tasks.dll" />

添加特定的转换目标:

<Target Name="ConfigDev">
    <TransformXml Source="web.config" Transform="web.dev.config" Destination="web.config" /></Target>

做一些转变,例如在ASPNETCORE_ENVIRONMENT的变量web.dev.config

<system.webServer>
    <aspNetCore processPath="dotnet" arguments=".\Test.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" >
      <environmentVariables>
        <environmentVariable xdt:Locator="Match(name)" name="ASPNETCORE_ENVIRONMENT" value="dev" xdt:Transform="SetAttributes" />
      </environmentVariables>
    </aspNetCore>
</system.webServer>

在运行发布之前使用msbuild转换 web.config:

msbuild Test.csproj /t:ConfigDev

“让我先说我不喜欢 web.config,但是将 AspNetCore 应用程序发布到 IIS 的经验真的很差。”

我完全同意这个话题。

在常规 ASP.Net 中配置转换的简单性之后,对机器范围ASPNETCORE_ENVIRONMENT变量的整个依赖很

甚至微软自己的例子也说我们可以使用,比如说,一个 _appsettings.Production.json_ 文件,只需添加这一行......

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

...但它不关心我们选择的配置的名称。 所以即使我选择了我的生产配置,它仍然会尝试打开 appsettings.development.json。 不,我不想每次发布到不同的环境时都自己手动编辑ASPNETCORE_ENVIRONMENT变量。 那只是自找麻烦。

我还没有看到一个使用 _appsettings.XXXX.json_ 文件的简单、有效的例子。
我等不及这些东西终于完成了。 (叹...)

是的,请解决这个问题!!

我刚刚部署了我的第一个生产 dotnet 核心站点,现在面临的问题是我无法在同一台服务器上轻松拥有临时实例,因为我不知道如何将我的应用程序发布到同一个盒子上生产设置。

我想我现在要尝试@DaleMckeown解决方案,我认为它会起作用,但它确实感觉像是一种解决方法而不是解决方案。 环境变量很好,但前提是您的服务器与环境的比例为 1-1,而且在企业之外,我怀疑这种情况经常发生。

@willapp我的建议绝对是一种解决方法。 但它确实有效 - 我已经在同一台服务器上运行了同一应用程序的多个版本,现在没有任何问题。

请记住在发布之前更改“ActiveEnvironment”设置,您应该没问题。

我正面临着 dkent600 提到的问题:

<environmentVariables>
      <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
</environmentVariables>

在生产服务器上不起作用。 应用程序一直使用“appsettings.Development.json”值,最终在发布时失去了 xml 转换的好处。

我将尝试 DaleMckeown 建议的解决方法。

更改 ASPNETCORE_ENVIRONMENT 的唯一合理方法是使用 web.config

并不真地。 如果您需要在同一台机器上运行同一站点的多个实例,这里有一个更简单的方法

  • 我的核心网站

    • 垃圾桶

    • 日志

  • env.whatever

将您的 IIS 应用程序指向 bin 和 program.cs

.UseEnvironment(ReadEnvExtensionFromParentFolder())

而已。 您可以拥有任意数量的站点,部署到 bin 中而无需担心转换,甚至可以通过重命名 env.Whenver 来切换环境。

我赞成这个。 我为在测试环境中不起作用的生产服务器配置了 URL 重写。 我还没有找到一种发布方式来选择正确的 web.config 文件进行部署,我必须手动复制它。

这方面有什么进展吗? 从最初的报告到现在已经 13 个月了,现在 2.1.0 已经出现了,传统 IIS 托管的情况仍然很糟糕。 如果您使用 Azure,事情会非常顺利,但目前对于我托管的大部分站点而言,这不是一个选项。

似乎对于传统的 IIS 托管,在命令行上设置所需的环境(如上面的@evil-shrike)以及在任何.pubxml发布配置文件中设置是有益的。 正如@davidfowl所说,需要明确的是,这仅适用于web.config和 IIS,但这肯定仍然涵盖了安装基础的很大一部分。

目前我有一个使用Microsoft.DotNet.Xdt.Toolsweb.config翻译的非常脆弱的解决方案,但它需要每个环境的构建配置才能工作,并且在更新到 v2.1.0 后刚刚崩溃。

很高兴听到这方面是否有任何计划,如果有,它们是什么? 如果没有计划,或者还有很长的路要走,那么肯定有比我们目前被迫采用的脆弱/半手动方式更好的临时解决方案吗? 特别是对于部署到 QA 和登台,我真的很希望能够在 VS 中按下一个按钮并知道正确的事情正在发生,而不必依赖于头脑知识和手动流程。

我们目前没有任何计划,但是@nil4 的这个工具https://github.com/nil4/xdt-samples/看起来很不错。

@svallis你试过了吗?

人们想要设置环境的主要内容是什么?

@davidfowl是的,我当前的解决方案是使用您链接的工具,但是对于具有多个目标的项目发布到它需要每个环境的构建配置。 您需要不同的构建配置才能在csproj设置中锁定某些内容,就我而言,它通常与您的环境是一对一的关系。 例如:

  • 构建配置:调试 = 环境:开发
  • 构建配置:暂存 = 环境:暂存
  • 构建配置:发布 = 环境:生产

对于后两个,我然后有相应的web.{Build configuration}.configappsettings.{Environment}.json ,而web.{Build configuration}.config实际上只是一个 XDT 告诉web.config以适当的ASPNETCORE_ENVIRONMENT环境变量。 例如,继续上面的例子, web.Release.config看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <system.webServer>
    <aspNetCore>
      <environmentVariables>
        <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
      </environmentVariables>
    </aspNetCore>
  </system.webServer>
</configuration>

这实际上在命令行中都可以很好地工作。 运行dotnet publish -c Staging或其他任何会生成一个具有正确输出的文件夹,并且web.config根据需要进行转换。 虽然感觉可以简化。 如果在dotnet publish上有一个-iisenvironment开关,它为我们做了这件事,然后在 VS 发布中作为一个简单的文本框公开,它将消除管理构建配置、XDT、等对于传统的 IIS 托管情况手动。

不过,从 VS 内部来看,它目前似乎有问题。 我们目前根本无法从 VS 内部发布,即使它在 v2.0.0 上工作,我们也必须在发布前手动选择正确的构建配置。

@davidfowl从我的角度来看,理想情况下,我想在使用 Web 部署时将环境设置为发布配置文件的一部分。

我的第二个是,发布的选项将是理想的选择。 我什至没有使用@svallis描述的解决方法,因为我更喜欢通过 VS IDE 而不是命令行发布。

@willapp我正在使用的解决方案在 Visual Studio 中确实有效,但我正在测试的解决方案存在其他问题,这些问题导致 VS 出现问题 (https://github.com/aspnet/Home/issues/3190) . 对不起,如果我没有说清楚。 所有这些都是使用csproj中的工具进行设置的,命令行和 VS 都应该尊重这些工具。

终于开始尝试@davidfowl上面建议的工具,它有效! 👍

只需按照“项目级工具”部分下的https://github.com/nil4/dotnet-transform-xdt的说明进行操作(因为我还没有使用 2.1.0)。 我必须自己创建一个默认的 Web.config,因为我没有它(只是从部署时 VS 生成的一个复制它),然后创建了一个 Web.Debug.config,并通过转换将 ASPNETCORE_ENVIRONMENT 设置为 Development,嘿快点! 它部署转换后的配置,站点现在可以正确启动。

如果官方提供对此的支持会很好,但现在这正在做这项工作。

@davidfowl您指向的链接需要使用命令行进行发布。 我想使用 VS GUI 工具发布。 我不希望我的开发人员需要安装 cli 工具来发布项目。 如果不支持转换,则无法在 web.config 中指定 ASPNETCORE_ENVIRONMENT。 看看这个问题有多少赞成票,它应该进入积压。

@orobert91 VS 只是一个围绕命令行工具的 GUI。 我成功地使用https://github.com/nil4/xdt-samples/在 VS 内发布期间转换web.config 。 如果您为您的项目正确配置了它,那么它将从命令行和您的 IDE 中正确转换。

@svallis确实,误读了文档。 我已经通过简单的复制任务解决了我的问题:

  <Target Name="CopyFiles" AfterTargets="Publish">  
      <Copy SourceFiles="web.$(Configuration).config" DestinationFiles="web.config" />  
  </Target>   

有一个 msbuild 属性发布了环境名称的荣誉 -

$(环境名称)

(https://github.com/aspnet/websdk/blob/d7d73e75918ec3168bd3e5d519d0decc04675faf/src/Publish/Microsoft.NET.Sdk.Publish.Targets/netstandard1.0/TransformTargets/Microsoft.NET.Sdk.Publishtarget.TransformL7Files9 )。

现在,设置此属性后,我们所做的就是创建appsettings.$(EnvironmentName).json并将连接字符串信息添加到该文件(如果需要)。

展望未来,在发布期间设置此属性时,我们还可以更新已发布的 web.config 以包含以下条目:

<environmentVariables>
      <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="$(EnvironmentName)" />
</environmentVariables>

这适用于这里提到的大多数场景吗?

对于设置 environmentVariable 之外的场景,我们将研究为核心项目移植 web.config 转换( Xdt )的可行性。

我想出了一个似乎涵盖了我需要的场景的解决方案 - 我想在这里发布它,以防它对其他人有帮助。

就我而言,我在本地有我的开发环境,在远程服务器(同一台服务器)上有我的登台和生产环境。 我能够从IApplicationBuilder提取应用程序 url 并在switch语句中使用它来设置EnvironmentName值。

与提供的其他一些解决方案相比,它似乎更不“变通”,但肯定归结为偏好。

Startup.cs

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            env.DetectAndSet(app);

            ... other config method stuff here ...
        }

上面的方法是我根据IApplicationBuilder的属性集合组合在一起的扩展。 扩展方法(和类)如下所示:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Hosting.Server.Features;
using System.Linq;

namespace MyRootNamespace.Common.Extensions
{
    public static class IHostingEnvironmentExtensions
    {
        /// <summary>
        /// Detects the current hosting url and sets the <see cref="IHostingEnvironment.EnvironmentName"/> accordingly.
        /// </summary>
        /// <param name="env">The <see cref="IHostingEnvironment"/> to set.</param>
        /// <param name="app">The <see cref="IApplicationBuilder"/> used to retrieve the current app url.</param>
        public static void DetectAndSet(this IHostingEnvironment env, IApplicationBuilder app)
        {
            var _appUrl = string.Empty;

            try
            {
                _appUrl = ((FeatureCollection)app.Properties["server.Features"]).Get<IServerAddressesFeature>()?.Addresses?.FirstOrDefault();
            }
            catch { }

            switch (_appUrl)
            {
                case "https://www.myurl.com":
                case "http://www.myurl.com":
                    env.EnvironmentName = EnvironmentName.Production;
                    break;
                case "https://staging.myurl.com":
                case "http://staging.myurl.com":
                    env.EnvironmentName = EnvironmentName.Staging;
                    break;
                default:
                    env.EnvironmentName = EnvironmentName.Development;
                    break;
            }
        }
    }
}

我希望这对人们有用(在那些不需要web.config转换的情况下)。

干杯!

我将此问题标记为讨论,因为目前没有计划与此相关的功能/修复。 如果人们仍然有特定的功能请求,请为这些提交问题,我们会优先考虑。

我对我在这个线程上看到的解决方法并不满意,所以我采取了不同的方法。 我偶然发现了这个线程堆栈溢出: https :

我们的内部 IIS 服务器由我们的运营团队管理,因此我们组织中的开发人员无论如何都不会创建这些站点。 运营团队使用 PowerShell 脚本来创建这些站点。 我只是要求他们修改该脚本,以便在配置站点时也对 ApplicationHost.config 进行相关更改。 现在我可以直接在那里部署而不必担心管理 .NET Core 环境。 对我们的情况很有效。

我认为在真正的 DevOps 环境中,您可能无论如何都会使用 Azure,这使得设置环境变量变得非常容易。

使用最新的 Sdk,您只需传递 msbuild 属性$(EnvironmentName) ,工具将负责将 ASPNETCORE_ENVIRONMENT 设置为该值。

例如:如果 EnvironmentName 设置为 staging,则 web.config 将具有以下条目:

      <aspNetCore processPath="dotnet" arguments=".\WebApplication242.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout">
        <environmentVariables>
          <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Staging" />
        </environmentVariables>
      </aspNetCore>

PR 与修复:
https://github.com/aspnet/websdk/pull/377

@vijayrkn看起来是一个有希望的开始。 这最终会支持 VS WebDeploy/发布配置文件等吗?

现在,我们在 VS 中没有 UI 来选择此环境名称,但是如果将其添加到项目文件或 pubxml 中,则从 VS 和命令行发布都将遵守它。

我们也将考虑为此添加 UI 支持。

@vijayrkn这只是针对使用web.config文件发布的人的解决方案 - 对吗?

@vijayrkn是的,获得对pubxml格式的支持将是这对我们的用例有用的时刻。 那时我们可以删除所有 XML 转换内容,只需在每个pubxml指定适当的环境字符串。 UI 支持可能会在以后提供,但这只是锦上添花。

@challamzinniagroup - 不,此功能不需要 web.config。
您需要做的就是将以下内容添加到 pubxml 文件中,然后发布工具将负责其余的工作。

<EnvironmentName>YourCustomEnvironment</EnvironmentName>

@challamzinniagroup@vijayrkn

除非你有一些配置只能在 web.config 中完成,并且必须在环境之间转换,否则,不要管 web.config。 使用 2 行代码,您可以从任何地方读取环境变量。 而且您不需要在发布配置文件或已发布代码中进行任何调整,只需匹配 appsetting.XYZ.json 的列表

@ThisNoName

您的意思是像数据库连接字符串、服务端点、凭据或任何其他可能会从开发-> 暂存-> 生产发生变化的东西。

如果您在同一个环境中运行多个实例(在云之外常见),您绝对需要 web.config 转换的灵活性。 微软并没有用 dotnet core 开箱即用地满足这个要求,这真是太荒谬了,他们只是假设每个人都在 Azure 中托管,并且实例和环境之间有 1-1 的关系。

环境变量实际上在云之外很糟糕,因为您最终将配置与您的应用程序分开,这使得管理部署变得更加困难。

这里的主要变化是这些秘密永远不应该存储在源代码控制中,而应该在环境本身上进行配置。 Transforms 与良好实践背道而驰,因为它假设您在发布时了解部署目标,但情况并非总是如此(尤其是当您有多个环境时)。 当您更改这 N 个部署之一的配置设置时,您真的需要重新部署吗?

现在不幸的是,对于 IIS,需要在配置文件中设置环境变量,以便应用程序池可以看到它们。 我认为我们从来没有打算让人们在目标机器上设置机器范围的配置(尽管我已经看到人们这样做了)。

@willapp你为什么不使用appsettings.json

@willapp

M$ 有完美的解决方案,但大多数人坚持 web.config 转换的概念。

这是您可以并排拥有多个站点的一种方法。 您只需要将您的环境值扔到 IIS 二进制目录之外的任何位置,然后从 program.cs 读取/设置它

  • 根目录

    • 我的网站开发

    • 垃圾桶



      • appsettings.json


      • appsettings.DEV.json


      • appsettings.PROD.json


      • 网页配置



    • 日志

    • 环境开发

    • 我的网站制作

    • 垃圾桶



      • appsettings.json


      • appsettings.DEV.json


      • appsettings.PROD.json


      • 网页配置



    • 日志

    • 环境生产

@davidfowl

您是在告诉人们不幸的是 ASP.NET 核心不能与 IIS 一起工作吗? 作为 Microsoft .NET Core 架构师?

任何 Core 的范式转变都是多平台的。 IIS 显然是一个 Windows 实用程序 - 因此应该会遇到一些成长的烦恼。 在这种情况下,随着事情的发展,应该预期并接受变通方法。 在 Core 中做出有意的设计选择以支持 Windows 功能将是违反直觉的 imo。

编辑添加:
这是关于 Core 是否应该更好地支持 IIS 的开箱即用的想法。 尽管讨论了使用环境变量是一个很好的选择......

@davidfowl

而这正是企业架构和中小企业的区别。 我为 FTSE100 工作,是的,将部署与代码分开是有道理的,但我也独立运行多个站点,拥有一台服务器来托管我的所有站点更容易且更具成本效益。 使用 Web Deploy + Transforms 是一种久经考验的交付代码更改机制,它确实有效。 我并不是说在某些情况下没有更好的替代方案,但微软应该继续支持转换,因为知道大多数用户在从 .net 框架迁移到核心时需要熟悉。

我现在已经有了这个线程前面的解决方案,所以我很高兴。 我只是认为他们丢球有点不包括这作为标准。

@willapp

我认为转换是基于从源代码编译并为每个环境单独发布的想法。 我很高兴 M$ 放弃了它,因为替代方案更加优雅。

使用新设置,您只需使用发布配置发布一次代码。 所有正在运行的实例都是原始实例的相同二进制副本。 部署应该只是简单的文件同步到下一个环境 DEV=>TEST=>Staging=>PROD。

您是在告诉人们不幸的是 ASP.NET 核心不能与 IIS 一起工作吗? 作为 Microsoft .NET Core 架构师?

我是说人们不会立即想到这样一个事实:像这样使用的环境变量应该是每个进程而不是每台机器。 从历史上看,人们在 Windows 上将环境变量识别为机器范围而不是每个进程,这引起了混乱。 IIS 10 添加了对添加每个应用程序池环境变量的支持。 ASP.NET Core 模块还支持为每个进程设置环境变量。

这种能力仍然存在。 我认为这里的思想主要发生了哲学上的转变。 我们不想做任何使在开发时指定机密变得更容易的事情。

@challamzinniagroup很好的总结

这是关于 Core 是否应该更好地支持 IIS 的开箱即用的想法。 尽管讨论了使用环境变量是一个很好的选择......

对。 配置环境特定信息的工作流仍应在特定环境上。 问题是你如何得到它。 它是部署的一部分吗?

综上所述,我相信我们会在 2.2 的工具中添加对此的支持。

抄送: @vijayrkn

@davidfowl

当您说“历史上在 Windows 上人们将环境变量识别为机器范围而不是每个进程”时,您的意思是 Windows 环境变量,如命令行 SET 中那样吗?

因为我对 .NET 核心上下文中的“环境”的理解只是一个变量。 默认情况下,它从系统或 web.config 读取 ASPNETCORE_ENVIRONMENT。 但是您可以通过任何约定从任何来源覆盖和获取它。

这种方法有什么本质上的错误吗? 因为如果微软.NET团队的官方立场是不做,我们就得认真考虑了。 但是你最终会告诉人们在 IIS 下运行 .NET 核心,但不幸的是,没有简单的方法来配置这些应用程序。 希望不是这样。

谢谢。

@ThisNoName

当您说“历史上在 Windows 上人们将环境变量识别为机器范围而不是每个进程”时,您的意思是 Windows 环境变量,如命令行 SET 中那样吗?

是的,这正是这个线程的全部内容。 (见这里)。 正如大卫所说,这些可以是每个进程,但根据我的经验,关于 dotnet core 的大部分文档都假设您在机器级别设置它们,因此我们遇到了这个问题,您无法轻松地将多个应用程序实例部署到同一服务器,如它们将获取相同的环境值,因此您无法区分 dev/staging/prod。

IIS10 支持按应用程序池设置它们这一事实很棒……如果您有可用的 Server 2016。 我正在运行 2012,所以这不是一个选项。 同样,我的问题不是 Microsoft 试图将事情朝着更好的方向发展,而是放弃对很多人在部署 ASP.NET 应用程序时认为理所当然的“传统”支持对我来说是一个错误。 无论如何都要引入新模式并鼓励人们采用它们,但在您确信很少有人需要它之前不要删除遗留行为。 否则,您所做的就是为想要 dotnet 核心但发现迁移路径太痛苦的客户设置障碍。

@willapp

这只是默认的开箱即用设置。 您可以随心所欲地阅读和设置环境。 至少这是我的理解,除非有人指出这种方法有任何严重缺陷?

   public class Program   {
        public static void Main(string[] args)   {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args)   {
               return WebHost.CreateDefaultBuilder(args)
                .UseEnvironment(ReadEnvFromWherever())
                .UseStartup<Startup>()
        }

        private string ReadEnvFromWherever() { 
              // Get and return whatever by your own convention
              return "DEV";
        }
    }

@ThisNoName

严重的缺陷是,根据您的解决方案配置,在使用来自 VSTS 的 Web 发布进行部署时,您如何使“ReadEnvFromWherever”方法返回不同的值? 我想你可以使用预处理器指令(#if RELEASE ...),但这感觉很脏。

在“旧世界”(ASP.NET 完整框架)中,您创建一个发布配置文件,其中一部分是选择要构建的解决方案配置。 然后根据该配置应用配置转换,允许您根据是否发布到 dev/staging/prod 来指定不同的配置。

我接受这个工作流程不适合现代 CI 管道,在那里你需要一个构建包并将它推送到每个环境 - 在这种情况下,你想要像 VSTS 发布管道这样的东西在部署时注入设置,或者你准备好您的服务器实例具有正确的环境变量,在这种情况下,您只需将包放到盒子上,它就会自动神奇地工作。 尽管如此,我认为很多 SME 和单人乐队并不在这个地方,并且希望从 Visual Studio 部署一个过程来产生他们想要的结果。

补充一点,这对于将小型项目部署到在 IIS 上运行并传统上提供 ASP.NET 托管的共享托管平台也很重要。 他们没有任何设施可以通过他们的托管控制面板为每个网站设置环境变量,因此唯一现实的方法是使用转换和web.config

听起来这一切在下一个版本中都会有一个不错的解决方案,并且内置 VS 支持会更进一步。 希望这将支持依赖此功能的现有工作流程的人们,直到可以升级或改进托管提供商和遗留系统。

@willapp

按照惯例。 如果您按照我之前发布的示例进行操作,您可以从父文件夹读取 env.DEV 并使用文件扩展名作为您的环境变量。 但是您可以按照任何约定进行,例如将您的应用程序根命名为 MySiteDEV、MySitePROD 等,并解析文件夹名称以获取环境名称。

如果您的代码因环境而异,您可以从 IHostingEnvironment .EnvironmentName 读取环境值

这与 .NET 核心从系统变量或 web.config 读取 ASPNETCORE_ENVIRONMENT 没有区别。

@ThisNoName

但是除了手动复制之外,如何将 _env.DEV_ 放入父文件夹? 我明白你想说什么,但我觉得你在这里缺少了这一点:过去有那只是工作一个彻头彻尾的现成解决方案。 现在没有,因为对它的工具支持未被视为 dotnet 核心部署过程的一部分。

我知道_为什么_它被删除了(因为如果你有一个不错的 CI 过程,还有更好的选择),但认为当很多迁移用户仍然想要它时,它是非常短视的。

@willapp

您在初始设置期间将其复制一次,所有未来的部署都将进入 bin 文件夹。 没有重新编译,没有发布,没有转换。 应该是这样,需要额外的 3 行代码,那又怎样? 这是百万美元。 直到 3 个月前,您甚至无法在 .NET Core 中调用 Active Directory。

@ThisNoName你希望被这 M$ 的东西认真对待吗? 你确实意识到现在是 2018 年,对吧?

在将 Web 部署到共享托管平台的上下文中,您的建议没有任何意义。 我什至不确定你在争论什么,该功能正在被添加到 ASP.NET Core 的下一个版本中,以便可以在发布配置文件中指定环境变量,不需要任何转换或任何东西。 也不需要使用文件夹名称的非标准方法,这可能在您的控制之下,也可能不在您的控制之下。

@willapp , @svallis
我进一步发布的解决方案在某些情况下有效。 您可以拉取 Url 并根据它设置环境。 在任何托管环境中,您都可以完全控制您的网址。 我意识到这仍然是“hackish”,并且是一种解决方法 - 但它通常应该在大部分时间有效。 就我的托管公司而言,我收到的 Url 是一个localhost:port base ("127.0.0.1:7777") - 所以它对我来说并不理想。 但我也有能力在我的各种环境中设置根文件夹路径,因为我将它们设置为子域 - 并且拉取根应用程序路径也非常简单:

        public static string DetectAndSet(this IHostingEnvironment env, ILogger logger)
        {
            switch (env.ContentRootPath)
            {
                case "h:\\root\\home\\www\\api":
                    env.EnvironmentName = EnvironmentName.Production;
                    break;
                case "h:\\root\\home\\www\\api-staging":
                    env.EnvironmentName = EnvironmentName.Staging;
                    break;
                default:
                    env.EnvironmentName = EnvironmentName.Development;
                    break;
            }

            logger.LogInformation($"Application root path discovered as '{env.ContentRootPath}'. Environment set to '{env.EnvironmentName}'");

            return env.EnvironmentName;
        }

是否应该在代码中、部署时确定环境或提前在环境中直接预先确定环境的选择不是我想要解决的讨论 - 我只是为那些 SME/主机控制有限且需要修复的个人。 就我而言,这是一个一次性代码——正是我所需要的。

在下游,我可以轻松地从appsettings.json文件中提取配置值,无需任何转换,包括:

"{configName}.{environmentName}": "{value}"

在设置文件中,每个配置有 3 个条目 - 每个环境一个。 我在这个文件中只有很少的配置,所以重复不是什么大问题。

希望这可以帮助!

@challamzinniagroup 按照惯例使用相对文件夹路径和名称更容易。

@svallis整个概念是发布一次并在二进制级别部署。 因此,即使您可以为每个发布配置文件设置变量,这也不是可行的方法。

@ThisNoName对你来说,也许更容易——但不要为别人假设这样的事情。 就我而言,我在发布/复制之前设置了清除目标目录的设置 - 因此对于您的解决方案,我每次都必须手动重新上传每个环境文件。 这绝对_不_更容易。

@challamzinniagroup同意。 每种情况都不同。 底线是环境只是一个变量,您可以以任何您认为合适的方式控制它,而不是等待微软提供下一个最好的东西。 不管它们出现什么,无论如何都只是另一个基于约定的解决方案——从系统或 web.config 读取一些值并设置环境。

顺便说一句,您仍然可以使用约定。 没有说 appsettings 必须使用单个中间词,并且 Staging/Production 没有特殊含义。 您可以轻松地执行此类操作并传入文件夹名称以进行匹配。

appsettings.api.json
appsettings.api-staging.json

使用基于约定的解决方案,您可以启动新实例而无需重新编译和/或重新发布。

@vijayrkn你能详细说明一下使用 pubxml 吗?
我将我的 SDK 升级到 2.1.302 (x64) 更改了我的 pubxml,但在发布的 web.config 上看不到任何差异。

@wggley - 该修复在 2.1.302 中不可用。 它应该会在下一个即将发布的版本中提供。

您可以从这里尝试包含修复程序的 cli 预览版 - https://dotnetcli.blob.core.windows.net/dotnet/Sdk/release/2.1.4xx/dotnet-sdk-latest-win-x64.exe

如果您在使用上述预览版时遇到任何问题,请告诉我。

谢谢@vijayrkn,我会等待下一个即将发布的版本并尝试在新发布中使用。
我想指出@frankhoffy解决方案对我来说就像一个魅力:
https://stackoverflow.com/questions/31049152/publish-to-iis-setting-environment-variable/36836533#36836533
寻找第一个答案(投票最多的答案)。

发布期间的 Web 配置转换支持现在在 2.2 preview1 中可用https://www.microsoft.com/net/download/dotnet-core/2.2

@vijayrkn某处有基本样本吗? 使用设置 ASPNETCORE_ENVIRONMENT 的基本转换将人们指向 hello world 等效项会很棒。

要设置 ASPNETCORE_ENVIRONMENT,用户可以设置 msbuild 属性“$(EnvironmentName)”。 我将添加一个示例,展示如何使用 web.config 转换设置其他环境变量。

这是一个示例存储库 - https://github.com/vijayrkn/webconfigtransform

自述文件详细说明了其工作原理:
https://github.com/vijayrkn/webconfigtransform/blob/master/README.md

希望这可以帮助!

@Eilon - 我们可以关闭这个问题。 这是已修复并在最新预览版中可用。

@vijayrkn不清楚如何配置发布设置以从发布设置对话框设置环境? 如果两个站点都部署到同一台服务器,那么在此对话框中实际上可以更改什么来区分临时站点和生产站点?

.NET 核心的这方面看起来很混乱。 需要更容易地在每个文件夹的基础上指定环境。 整个服务器环境变量根本无法适应我们的情况。 并非每个人都可以在与其生产站点不同的服务器上运行他们的临时站点。

该设置是针对每个应用程序的。

抱歉,但这并不能真正回答我的问题。 也许我误解了一些东西。

这里有一些伪文件https://github.com/vijayrkn/webconfigtransform/blob/master/README.md (@vijayrkn我们需要进入真正的文档这一点)。

@vijayrkn在发布对话框中对此有多少支持?

目前,发布对话框不支持设置发布环境,但可以在发布配置文件中手动设置环境,也可以应用特定的转换。

@nmg196 - 如果您只想在 web.config 中设置“ASPNETCORE_ENVIRONMENT”,您所要做的就是将环境名称添加到发布配置文件中。

例子:
https://github.com/vijayrkn/webconfigtransform/blob/master/Properties/PublishProfiles/FolderProfile.pubxml#L18

对于高级场景(除了设置 ASPNETCORE_ENVIRONMENT 环境变量),可以应用 web.config 转换,如上述文档中所述。

@davidfowl - Angelos 有一个项目可以记录 web.config 转换支持。

@vijayrkn如何在 TFS 的 CI/CD 中使用? 我无法在 TFS 中使用 p:CustomTransformFileName 发布 dotnet

您可以将此 msbuild 属性传递给 dotnet publish。

您可以在此处参考此示例 - https://github.com/vijayrkn/webconfigtransform/blob/master/publish.cmd

这会将 CustomTransformFileName 属性传递给 dotnet publish

dotnet publish /p:Configuration=Release /p:EnvironmentName=Staging /p:CustomTransformFileName=custom.transform

@vijayrkn
我已阅读您的文档,但无法让 web.config 进行转换。 我基本上已经尝试了 readme.md 中的所有命令,但没有一个会导致执行转换。

然而,我已经能够编写一个 powershell 脚本,它使用 Microsoft.Web.XmlTransform.dll 来执行与发布操作分开的转换。

我的问题是您使用的
我在用:
dotnet --version 2.1.104
dotnet msbuild-版本 15.6.84.34536

谢谢

@davidfowl写道:

这里有一些伪文件https://github.com/vijayrkn/webconfigtransform/blob/master/README.md (@vijayrkn我们需要进入真正的文档这一点)。

@vijayrkn在发布对话框中对此有多少支持?

你知道这是否曾经被添加到真正的文档中,如果是,你有链接吗?

我们现在已经转而在我们的发布配置文件中使用<EnvironmentName> 。 不过,最好在此之上有一些 UI,以便它更显眼。 我想这会在以后出现吗?

我认为在 dotnet 发布上默认启用 web.config 转换是一项重大更改。 安装 .NET Core SDK 2.2.101 后,它破坏了我们的 CI/CD 方案。 我们的管道配置为仅使用dotnet publish为任何发布创建一次发布的工件(dotnet publish和发布管理工具。

使用<IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>设置禁用 web.config 转换后,TransformWebConfig 也跳过(与 TransformXml 一起),这导致%LAUNCHER_PATH%%LAUNCHER_ARGS%变量在发布过程中没有被替换。 是否有独立控制这些步骤的设置?

这是否适用于带有 App.Config 文件的控制台应用程序?

我们可以看一个例子吗?

@dmitryshunkov您可以将 $(RunXdt) 设置为 false 以跳过运行自定义 Xml 转换。

@auserx - 如果它是一个 sdk 风格的项目,那么它应该可以工作。

此页面是否有帮助?
0 / 5 - 0 等级