Web 配置转换不起作用

Posted

技术标签:

【中文标题】Web 配置转换不起作用【英文标题】:Web Config Transform not working 【发布时间】:2012-02-09 02:18:10 【问题描述】:

在 .NET MVC 3.0 应用程序中,我在 appSettings 中有以下配置:

web.config

<appSettings>
<add key="SMTPHost" value="mail.domain.com"/>
    <add key="SMTPUsername" value="user@gmail.com"/>
    <add key="SMTPPort" value="25"/>
    <add key="SMTPPwd" value="mypassword"/>
    <add key="EmailFrom" value="notific@gmail.com"/>
</appSettings>

为了调试,我定义了以下配置转换:

web.Debug.config

<appSettings>
    <add  key="SMTPPort" value="58" xdt:Transform="Replace" xdt:Locator="Match(key)" />
</appSettings>

我在调试模式下运行应用程序,但我的 SMTP 端口仍然从web.config 获取值,而不是web.Debug.config

谁能建议这个配置有什么问题?

【问题讨论】:

【参考方案1】:

Web.config 转换仅作为发布操作的一部分应用。

如果您希望将此作为app.config 构建操作的一部分完成,那么您可以使用 SlowCheetah - XML Transforms Visual Studio 插件:

http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5

【讨论】:

非常感谢您为我节省了很多时间。 哇,我花了 2 个小时才找到这个答案。感谢您发布它,我会一直把我的头发拉出来。 似乎在 Visual Studio 2015 中 (Web).config 转换 现在是内置功能,因此您不再需要 SlowCheetah。但内置转换仅在您发布应用程序时应用,而不是在您运行它时应用。你可以看看here我是怎么解决的。 不知道为什么要使用它,而@komsky 的回答提供了一个简单而干净的解决方案。 SlowCheetah 很棒,但从他们自己的文档来看:“对于 web 项目,当您发布或打包应用程序时,文件会被转换。”换句话说,不是在调试时。【参考方案2】:

Visual Studio (2010 - 2019) 很遗憾 在您调试时直接支持它,它仅用于发布 - 即使它使用了扩展 SlowCheetah(标记答案)不适用于我(仅适用于使用 app.config 而不是 web.config 的项目)。

注意,有一个解决方法 described at codeproject。

它描述了如何修改 .msproj 文件以用转换后的版本覆盖当前的 web.config。

我将首先将该解决方法描述为 Option 1,但我最近发现了另一个 Option 2,它更易于使用(因此您可以向下滚动到 option 2如果你喜欢直接):


选项 1: 我添加了从原始 codeproject 文章 中获取的说明(请参阅上面的链接),因为那里的屏幕截图已经消失了,我没有'不想丢失全部信息:

在您开发和调试本地环境时,VS.Net 不会进行任何转换。但是,如果您愿意,可以采取一些步骤来实现这一点。

首先,在 VS.Net 中创建您想要的配置,假设默认的调试和发布不足以满足您的要求。 右键单击您的web.config 并选择添加配置转换 - 这将为您定义的每个配置创建一个依赖转换配置。 现在您可以将您的 web.config 重命名为 web.base.config。 将web.config 添加到您的项目中。里面有什么并不重要,因为每次我们进行构建时它都会被覆盖,但我们希望它成为项目的一部分,所以 VS.Net 不会给我们 “你的项目未配置调试” 弹出窗口。 编辑您的 .csproj 项目文件,并将以下 TransformXml 任务添加到 AfterBuild 目标。在这里你可以看到我将使用web.[configuration].config 转换web.base.config 文件并将其保存为web.config。详情请查看thisMicrosoft Q&A,有关如何扩展构建的说明请查看there。

选项 2:

基于this 的回答,我开发了一个简单的控制台应用程序TransformConfig.exe(C# 6.0 语法):

using System;
using System.Linq;
using Microsoft.Web.XmlTransform;

namespace TransformConfig


  class Program
  
    static int Main(string[] args)
    
        var myDocumentsFolder = $@"C:\Users\Environment.UserName\Documents";
        var myVsProjects = $@"myDocumentsFolder\Visual Studio 2015\Projects";

        string srcConfigFileName = "Web.config";
        string tgtConfigFileName = srcConfigFileName;
        string transformFileName = "Web.Debug.config";
        string basePath = myVsProjects + @"\";
        try
        

            var numArgs = args?.Count() ?? 0;
            if (numArgs == 0 || args.Any(x=>x=="/?"))
            
                Console.WriteLine("\nTransformConfig - Usage:");
                Console.WriteLine("\tTransformConfig.exe /d:tgtConfigFileName [/t:transformFileName [/s:srcConfigFileName][/b:basePath]]");
                Console.WriteLine($"\nIf 'basePath' is just a directory name, 'basePath' is preceeded.");
                Console.WriteLine("\nTransformConfig - Example (inside PostBuild event):");
                Console.WriteLine("\t\"c:\\Tools\\TransformConfig.exe\"  /d:Web.config /t:Web.$(ConfigurationName).config /s:Web.Template.config /b:\"$(ProjectDir)\\\"");
                Environment.ExitCode = 1;
                return 1;
            

            foreach (var a in args)
            
                var param = a.Trim().Substring(3).TrimStart();
                switch (a.TrimStart().Substring(0,2).ToLowerInvariant())
                
                    case "/d":
                        tgtConfigFileName = param ?? tgtConfigFileName;
                        break;
                    case "/t":
                        transformFileName = param ?? transformFileName;
                        break;
                    case "/b":
                        var isPath = (param ?? "").Contains("\\");
                        basePath = (isPath == false)
                                    ? $@"myVsProjects\" + param ?? ""
                                    : param;
                        break;
                    case "/s":
                        srcConfigFileName = param ?? srcConfigFileName;
                        break;
                    default:
                        break;
                
            
            basePath = System.IO.Path.GetFullPath(basePath);
            if (!basePath.EndsWith("\\")) basePath += "\\";
            if (tgtConfigFileName != srcConfigFileName)
            
                System.IO.File.Copy(basePath + srcConfigFileName,
                                     basePath + tgtConfigFileName, true);
            
            TransformConfig(basePath + tgtConfigFileName, basePath + transformFileName);
            Console.WriteLine($"TransformConfig - transformed 'basePath + tgtConfigFileName' successfully using 'transformFileName'.");
            Environment.ExitCode = 0;
            return 0;
        
        catch (Exception ex)
        
            var msg = $"ex.Message\nParameters:\n/d:tgtConfigFileName\n/t:transformFileName\n/s:srcConfigFileName\n/b:basePath";
            Console.WriteLine($"TransformConfig - Exception occurred: msg");
            Console.WriteLine($"TransformConfig - Processing aborted.");
            Environment.ExitCode = 2;
            return 2;
        
    

    public static void TransformConfig(string configFileName, string transformFileName)
    
        var document = new XmlTransformableDocument();
        document.PreserveWhitespace = true;
        document.Load(configFileName);

        var transformation = new XmlTransformation(transformFileName);
        if (!transformation.Apply(document))
        
            throw new Exception("Transformation Failed");
        
        document.Save(configFileName);
    

  

确保添加 DLL "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.XmlTransform.dll"作为参考(此示例适用于 VS 2015,对于旧版本,将路径中的 v14.0 替换为适当的版本号,例如 v11.0)。

对于 Visual Studio 2017,路径的命名架构已更改:例如,对于企业版,它位于此处:C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\VisualStudio\v15.0\Web。 我假设对于专业版,您需要将路径中的Enterprise 替换为Professional。如果您使用的是预览版,请另外将2017 替换为Preview

以下是 Visual Studio 不同版本的路径如何更改的概述(如果您没有企业版,则可能需要将路径中的 Enterprise 替换为 Professional):

VS 版本        路径(用于Microsoft.Web.XmlTransform.dll 2015                  C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\Web 2017                  C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\VisualStudio\v15.0\Web 2019                  C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VisualStudio\v16.0\Web

编译它并将.exe文件放入一个目录,例如C:\MyTools\.

用法: 您可以在构建后事件中使用它(在项目属性中,选择构建事件,然后编辑构建后事件命令行)。命令行参数是(示例):

"C:\MyTools\TransformConfig.Exe" /d:Web.config /t:Web.$(ConfigurationName).config /s:Web.Template.config /b:"$(ProjectDir)\"

即首先是配置文件的名称,然后是转换配置文件,然后是可选的模板配置,然后是包含这两个文件的项目的路径。

我添加了可选的模板配置参数,因为否则您的原始完整配置将被转换覆盖,这可以通过提供模板来避免。

只需复制原始 Web.config 并将其命名为 Web.Template.config 即可创建模板。

注意:

如果您愿意,也可以将 TransformConfig.exe 文件复制到上述 Microsoft.Web.XmlTransform.dll 所在的 Visual Studio 路径,并在您需要转换配置的所有项目中引用它。

对于那些想知道我为什么添加 Environment.ExitCode = x; 分配的人:简单地从 Main 返回一个 int 对构建事件没有帮助。查看详情here.

如果您要发布项目并使用 Web.Template.config,请确保您在解决方案上使用正确的配置(通常是发布)进行了 重建你发布。原因是 Web.Config 在调试期间被覆盖,否则您可能最终会转换错误的文件。

【讨论】:

看起来 CodeProject 的帖子被坑了。他为他的代码示例使用了屏幕截图,现在自从他的博客关闭后,它们就被历史遗忘了。 是的,很遗憾,截图不见了。但至少文章文本仍然存在,描述了该方法。我已将文本描述添加到我的答案中以避免丢失。 是的,也许可以尝试联系 codeproject 的作者 James Coleman 来修复它。不过,不确定他是否还在那里活动。 @ThomasTeilmann 我认为这可能类似于丢失的屏幕截图中的内容。似乎达到了相同的基本结果。 ***.com/a/6437192/1003916【参考方案3】:

回答你的问题并不简单,因为它提出了一个问题——如果你想用 Web.debug.config 转换 Web.config——转换效果应该存储在哪里?在 Web.config 本身?这将覆盖转换源文件!可能这就是 Visual Studio 在构建期间不进行转换的原因。

以前的 Matt 答案是有效的,但您可能希望将它们混合以获得通用解决方案,当您实际将活动解决方案配置从调试更改为发布等时可以使用。这是一个简单的解决方案:

    为配置(调试、发布等)创建配置转换 将 Web.config 文件重命名为 Web.base.config - 转换应自动重命名(Web.base.Debug.config 等) 将以下 transformWebConfig.proj XML 文件添加到您的项目文件夹:
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" DefaultTargets="TransformWebConfig" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
  <Target Name="TransformWebConfig">
    <TransformXml Source="Web.base.config" Transform="Web.base.$(CurrentConfig).config" Destination="Web.config" />
  </Target>
</Project>
    导航到您的项目属性,选择构建事件并将以下内容添加到构建后事件命令行
@if exist "%ProgramFiles(x86)%\MSBuild\12.0\bin" set PATH=%ProgramFiles(x86)%\MSBuild\12.0\bin;%PATH%
msbuild $(ProjectDir)transformWebConfig.proj /t:TransformWebConfig /p:CurrentConfig=$(ConfigurationName) /p:TargetProjectName=$(TargetPath)

现在,当您构建解决方案时,将创建一个 Web.config 文件,其中包含用于活动配置的有效转换。

【讨论】:

最干净和最好的答案。一些问题: 1. 为什么 XML 验证表明 TransformXml 元素在 Target 元素中无效? (构建工作顺便说一句)。 2.现在生成了真正的Web.Config,我还是把Web.Config添加到项目中。现在,每当我在调试/发布之间切换时,web.config 都会发生变化,但我不一定想一直将其提交到源代码库中。 1.无法真正说出 VS 如何使用架构验证此 XML,但此警告很常见,因此您可以忽略它。 2. 这取决于你使用的是什么仓库,但你可以例如使用 git.ignore 文件条目。 这对我来说效果很好——只是将 build-event 和 proj 文件中的 12 更改为当前版本。对于我使用的构建后事件:'"$(MSBuildBinPath)\msbuild.exe" $(ProjectDir)TransformWebConfig.proj /t:TransformWebConfig /p:CurrentConfig=$(ConfigurationName) /p:TargetProjectName=$(TargetPath) 并在 .proj 文件中将v12.0 更新为v14.0 对于 VS 2017,将每个 12.0 修改为 14.0 1)不要忘记将生成的web.config包含在web项目中,否则发布后不会复制到目标文件夹。 2)如果构建服务器缺少这两个文件,只需将它们复制到服务器“Microsoft.Web.Publishing.Tasks”,“Microsoft.Web.XmlTransform”【参考方案4】:

对于 VS 2017,我找到了答案 here 不确定为什么没有人在上面引用它,因为它似乎是一个非常流行的解决方案。也很容易。请确保您在 2019 年 3 月 5 日看到 IOrlandoni 的评论,以使其在 VS 2017 和所有版本中运行。

基本上它是一个两个步进器。首先,编辑 .csproj 文件,添加下面的代码。其次,您创建一个新的 web.base.config 配置并将现有的 web.config 复制到那里。之后,任何构建都会用您想要的转换覆盖您的 web.config。

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\WebApplications\Microsoft.WebApplication.targets" />
<Target Name="BeforeBuild">
    <TransformXml Source="Web.Base.config" 
        Transform="Web.$(Configuration).config" Destination="Web.config" />
</Target>  

【讨论】:

这可能是最好的答案,但 IMO 它缺少一个技巧。如果您将Web.configContent 更改为None,那么您可以使用Source="Web.config" Destination="$(TargetPath).config"(或者对于某些类型的项目,Destination="$(TargetDir)Web.config")。我还将转换移动到AfterBuild,因为不再需要在复制文件之前完成它。 好的,实际上这不起作用,因为由于某种原因我无法将其配置为从 bin 运行。【参考方案5】:

您的直接问题已得到解答 - 解释是转换是在发布时应用的,而不是在构建时应用的。

但是,我认为它没有提供有关如何实现您想要做的事情的解决方案。

几天来,我一直在为这个确切的问题苦苦挣扎,寻找一种方法来保持 web.config 干净并在相应的转换文件中设置根据环境而变化的所有键。我的结论是,最简单和最稳定的解决方案是在原始 web.config 中使用调试值,这样当您在 Visual Studio 中进行调试运行时它们始终存在。

然后为您想要发布到的不同环境创建转换 - 测试、集成、生产 - 无论您拥有什么。现在内置的在发布时转换 web.config 文件的功能就足够了。无需 SlowCheetah 或编辑构建事件或项目文件。如果您只有网络项目。

如果您愿意,您还可以在解决方案中包含 web.debug.config 文件,只是为了保留一个单独的文件,其中包含与开发环境相关的所有值。请务必在其中注释,但在 Visual Studio 中运行时不会应用这些值,以防其他人尝试将其用于此目的!

【讨论】:

【参考方案6】:

最近我在使用基于 .NET Framework 2.0 的旧 web.config 文件时遇到了同样的问题。解决方案是简单地删除 web.config 的命名空间(xmlns 属性在 configuration 根节点):

之前:&lt;configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"&gt;

之后:&lt;configuration&gt;

【讨论】:

【参考方案7】:

要在构建时完成转换:

从您的项目中排除 web.config (+ web.*.config)。 然后重命名磁盘上的文件如下

web.config => Web.Template.config web.Release.config => Web.Transform.Release.config web.Debug.config => Web.Transform.Debug.config

将 web.config 添加到您的 gitignore 并提交到目前为止的更改。

最后,在文本编辑器中将以下内容添加到项目文件中。

  <Target Name="BeforeBuild">
    <TransformXml Source="Web.Template.config" Transform="Web.Transform.$(Configuration).config" Destination="Web.config" />
  </Target>
  <ItemGroup>
    <Content Include="Web.config" />
    <None Include="Web.*.config" />
  </ItemGroup>

现在,只要您在 Visual Studio 中选择了调试配置,Web.Template.config 就会被 Web.Debug.Transform.config 转换为 Web.config。 Release 也是一样。

第一次生成 Web.config 时,您可能需要在构建后重新启动 Visual Studio,然后再次构建以让 Visual Studio 识别生成的 web.config。

此方法已在 Visual Studio 2019 上使用 ASP.NET(非核心)项目进行了测试。

【讨论】:

听起来很酷。会试一试 为我工作。谢谢【参考方案8】:

显然有 Visual Studio 2015 的扩展

https://visualstudiogallery.msdn.microsoft.com/05bb50e3-c971-4613-9379-acae2cfe6f9e

此包使您能够根据构建配置转换您的 app.config 或任何其他 XML 文件

【讨论】:

SlowCheeta 不是新产品。它已经存在了很长时间。他们的 1.1 版本于 2011 年 9 月 8 日发布 @HaBo 感谢您的关注,我已将newworld 作为句子删除。【参考方案9】:

使用Octopus Deploy(社区版免费),让它为您转换web.config。步骤:

    Set up Octopus to deploy your web application 确保您的Web.Release.configBuild Action 属性设置为Content,就像您的主要web.config 文件一样。

就是这样! Octopus 将在没有任何特殊配置的情况下完成其余的工作。默认的 IIS 网站部署将立即执行此操作:

【讨论】:

数字 2 是关键 :)【参考方案10】:

添加到您的应用设置“xdt:Transform="Replace" 属性。 如下所示:

  <appSettings xdt:Transform="Replace">
       <add  key="SMTPPort" value="58" xdt:Transform="Replace" xdt:Locator="Match(key)" />
  </appSettings>

它将用调试配置替换整个 appsettings。但如果你不希望你可以应用任何你想要的标签。它将包括该标签的所有子元素。 顺便说一句,您还应该将属性设置为配置部分。我在下面标记:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">

【讨论】:

以上是关于Web 配置转换不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Spring web:Java8 LocalTime 的@RequestBody Json 转换不起作用

Debezium SMT 转换重新路由关键字段设置不起作用

通过 IIS 配置 Web 应用程序时,从剪贴板粘贴图像不起作用

Spring RestTemplate 连接超时不起作用

单点登录在 Spring Web 应用程序中不起作用

Spring Boot ReactiveCircuitBreaker 配置不起作用