95

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

网络配置

<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.

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

4

10 回答 10

167

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

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

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

于 2012-01-12T19:28:04.137 回答
35

不幸的是, Visual Studio(2010 - 2019)在您调试时直接支持它,它仅用于发布 - 即使扩展名为 SlowCheetah(标记答案)它对我也不起作用(仅适用于使用 app.config 而不是web.config)。

请注意,在 codeproject 中描述了一种解决方法

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

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


选项1:我添加了从原始代码项目文章中获取的说明(参见上面的链接),因为那里的屏幕截图已经消失了,我不想丢失整个信息:

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

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

选项 2:

基于这个答案,我开发了一个简单的控制台应用程序 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. 如果您使用的是预览版,请另外替换2017Preview.

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

VS 版本        路径 (for 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文件复制到上面提到的 Visual Studio 路径,Microsoft.Web.XmlTransform.dll并在您需要转换配置的所有项目中引用它。

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

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

于 2013-06-27T06:29:12.860 回答
24

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

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

  1. 为配置创建配置转换(调试、发布等)
  2. Web.config将文件重命名为Web.base.config- 转换应自动相应地重命名(Web.base.Debug.config等)
  3. 将以下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>
  1. 导航到您的项目属性,选择Build Events并将以下内容添加到Post-build event 命令行
@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 文件,其中包含用于活动配置的有效转换。

于 2016-01-21T15:05:58.157 回答
8

对于 VS 2017,我在这里找到了答案,不确定为什么没有人在上面引用它,因为它似乎是一个非常流行的解决方案。也很容易。确保您在 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>  
于 2019-05-31T21:20:22.503 回答
5

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

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

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

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

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

于 2017-06-01T08:39:08.387 回答
1

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

前:<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">

后:<configuration>

于 2018-02-15T16:43:06.643 回答
1

要在构建时完成转换:

从您的项目中排除 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。发行版也一样。

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

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

于 2021-09-18T08:16:14.507 回答
0

显然有 Visual Studio 2015 的扩展

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

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

于 2016-09-17T18:01:41.280 回答
0

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

  1. 设置 Octopus 以部署您的 Web 应用程序
  2. 确保您Web.Release.configBuild Action属性设置为Content就像您的主web.config文件一样。

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

于 2017-05-22T06:27:36.667 回答
-1

添加到您的 appsetting “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">
于 2021-12-28T15:37:57.380 回答