如何在 Visual Studio 中为自定义配置文件添加配置转换?

How to add config transformations for a custom config file in Visual Studio?

我正在从事的项目涉及从配置文件中读取大量服务端点 (url)。由于列表会非常大,我决定将它们保存在一个自定义配置文件中,以保持我的 web.config 干净和小巧。我将自定义部分包含在我的网站中,如下所示:

<mySection configSource="myConfig.config" />

我工作得很好。

但是在项目部署到不同环境的过程中出现了转换的问题。我有三个 web.config 个文件:

Web.config

Web.Uat.config

Web.Release.config

虽然转换 web.config 有效,但自定义配置文件的转换在部署时失败。

有没有一种方法可以在部署期间转换自定义配置文件?

Visual Studio 默认只转换 web.config 个文件。

如果您需要为 DEV、UAT、PROD 等环境转换的自定义配置文件,请尝试

  1. 使用 Visual Studio 的自定义扩展,例如 SlowCheetah - XML Transforms 的配置转换预览功能。
  2. 从 Nuget SlowCheetah 为项目添加以提供内置转换。

一点细节:

从扩展和更新中添加 VS 扩展 SlowCheetah

右键单击您的 myconfig.config 并选择添加变形:

在每个定义的配置中插入您自己的转换规则,如下所示:

<services xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <service name="WebApplication1.Services.Service2" xdt:Transform="Replace" xdt:Locator="Match(name)" >
    <endpoint address="http://localhost:57939/Services/DebugService" behaviorConfiguration="WebApplication1.Services.Service2AspNetAjaxBehavior"
      binding="webHttpBinding" contract="WebApplication1.Services.Service2" />
  </service>
</services>

希望对您有所帮助

我一直在使用 SlowCheetah,但我发现了一些我认为更优雅的东西。只是告诉构建根据构建配置生成 .config。

在您的项目中有一个 app.Release.config(或更多,具体取决于您的部署需要),您只需编辑项目文件(如果您使用 C# 编程,则为 .csproj 文件)。找到它的结尾,在最后一个 </ItemGroup></Project> 之间并添加:

  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
  <Target Name="AfterBuild">
    <PropertyGroup>
      <OutputTypeName>$(OutputType)</OutputTypeName>
      <OutputTypeName Condition="'$(OutputTypeName)'=='Library'">dll</OutputTypeName>
      <OutputTypeName Condition="'$(OutputTypeName)'=='Module'">dll</OutputTypeName>
      <OutputTypeName Condition="'$(OutputTypeName)'=='Winexe'">exe</OutputTypeName>
    </PropertyGroup>
    <TransformXml Source="Config\app.config" Transform="Config\app.$(Configuration).config" Destination="$(OutputPath)$(AssemblyName).$(OutputTypeName).config" />
  </Target>
</Project>

保存并从 VisualStudio 重新加载。在发布模式下编译并检查 <MyProject>.config 文件上的 bin/Release 文件夹,转换已完成。

此示例适用于 Exe 和 Dll 文件以及任何 VisualStudio 版本,因为包括 this post help

我将稍微扩展一下 Andoni Ripoll Jarauta 的回答。

我们遇到了类似的问题。我想从 web.config 文件中提取连接字符串以限制合并冲突。我还想在发布时创建一个包含静态信息的 "release" 配置。

...很简单。创建自定义配置文件 webdb.config,并更新 web.config 文件。

例如。 web.config

<connectionStrings configSource="WebDB.config"/>

wedbdb.config(转换需要xmlversion="1.0")

<?xml version="1.0" encoding="utf-8"?>
<connectionStrings>
</connectionStrings>

接下来为 webdb.config

添加转换文件

WebDB.Debug.config 示例:

<?xml version="1.0" encoding="utf-8"?>

<connectionStrings xdt:Transform="Replace" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <add name="PRRADDataContainer" connectionString="metadata=~/PRRADData.csdl|~/PRRADData.ssdl|~/PRRADData.msl;provider=System.Data.SqlClient;provider connection string=';Data Source=localhost;Initial Catalog=;User ID=;Password=;multipleactiveresultsets=True;App=EntityFramework';" providerName="System.Data.EntityClient" />
    <add name="MyConnectionString" connectionString="Data Source=localhost;Initial Catalog=;Persist Security Info=True;User ID=;Password=;" providerName="System.Data.SqlClient" />
</connectionStrings>

WebDB.Release.config 示例:

<?xml version="1.0" encoding="utf-8"?>

<connectionStrings xdt:Transform="Replace" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <add name="PRRADDataContainer" connectionString="metadata=~/PRRADData.csdl|~/PRRADData.ssdl|~/PRRADData.msl;provider=System.Data.SqlClient;provider connection string=';Data Source=prod_server;Initial Catalog=;User ID=;Password=;multipleactiveresultsets=True;App=EntityFramework';" providerName="System.Data.EntityClient" />
    <add name="MyConnectionString" connectionString="Data Source=prod_server;Initial Catalog=;Persist Security Info=True;User ID=;Password=;" providerName="System.Data.SqlClient" />
</connectionStrings>

接下来我们需要添加一个构建后事件。这是通过简单地编辑 CSPROJ 文件创建的。

<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterBuild">
    <TransformXml Source="WebDB.config" Transform="WebDB.$(Configuration).config" Destination="WebDB.config" />
</Target>

现在,当我在本地 运行 时,我会得到 WebDB.Debug.config,当我发布我的代码时,我只需要确保 select "Release" 作为配置源.在这两种情况下,WebDB.config 文件将在您构建时使用相应的文件进行更新。

注意:请确保将 webdb.config、webdb.debug.config 和 webdb.release.config 设置为 "Do not copy" 以获得 "Copy to Output Directory" 选项。

希望对您有所帮助!

还有另一种方法,不需要安装扩展,也不需要使用构建事件。

假设您有这样的自定义配置:

  • myConfig.config
  • myConfig.Uat.config
  • myConfig.Release.config

然后在你的主要Web.config你有这个:

<mySection configSource="myConfig.config" />

最后,在您的 Web.Uat.config 中添加如下转换:

<mySection configSource="myConfig.Uat.config" xdt:Transform="SetAttributes" />

这不是在转换 myConfig.config 文件,而是覆盖应该使用的自定义配置文件的名称。您可以对 Release 和任何其他环境执行相同的操作。

您的 myConfig.Uat.config 不应包含转换,它应该是基本自定义配置文件的副本,具有适合自定义环境的值。

缺点是每次向基本自定义配置文件添加内容时,您还需要向其他 envs 的配置文件添加内容(即使通过 envs 的值应该相同)。所以我会考虑只使用这些自定义配置文件来设置应该在 envs 之间更改。

由于 OP 在部署期间询问了 Web.config 转换,因此我们假设 WPP 已经存在。所以我黑了 WPP。

我使用以下代码片段来转换 Umbraco 自己的配置文件(但实际上任何配置都适合):

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <UmbracoConfigsToTransform Include="Config\umbracoSettings.config">
      <DestinationRelativePath>Config\umbracoSettings.config</DestinationRelativePath>
    </UmbracoConfigsToTransform>
  </ItemGroup>

  <PropertyGroup>
    <CollectWebConfigsToTransformDependsOn>
      $(CollectWebConfigsToTransformDependsOn);
      CollectUmbracoConfigsToTransform
    </CollectWebConfigsToTransformDependsOn>
  </PropertyGroup>

  <Target Name="CollectUmbracoConfigsToTransform">
    <!-- The logic comes from the 'CollectWebConfigsToTransform' task -->
    <ItemGroup>
      <WebConfigsToTransform Include="@(UmbracoConfigsToTransform)">
        <Exclude>false</Exclude>
        <TransformFile>$([System.String]::new($(WebPublishPipelineProjectDirectory)$([System.IO.Path]::GetDirectoryName($([System.String]::new(%(DestinationRelativePath)))))).TrimEnd('\'))\%(Filename).$(Configuration)%(Extension)</TransformFile>
        <TransformOriginalFolder>$(TransformWebConfigIntermediateLocation)\original</TransformOriginalFolder>
        <TransformFileFolder>$(TransformWebConfigIntermediateLocation)\assist</TransformFileFolder>
        <TransformOutputFile>$(TransformWebConfigIntermediateLocation)\transformed\%(DestinationRelativePath)</TransformOutputFile>
        <TransformScope>$([System.IO.Path]::GetFullPath($(WPPAllFilesInSingleFolder)\%(DestinationRelativePath)))</TransformScope>
      </WebConfigsToTransform>
    </ItemGroup>
  </Target>
</Project>

我将其命名为 Umbraco.wpp.targets 并放入项目的根目录中。 WPP 会自动导入它。

您接下来要做的就是添加一个转换文件(Config\umbracoSettings.Release.config 是这个示例的例子)。

我有类似的需要来转换自定义配置文件,但在 class 库中。 Andoni Ripoll Jarauta 的解决方案在我直接构建项目时有效,但是当我构建另一个引用它的项目时,转换后的文件不会被复制。我发现我还必须将转换后的文件添加到 AssignTargetPathsDependsOn 才能实现。这成功了:

<PropertyGroup>
  <AssignTargetPathsDependsOn>
    $(AssignTargetPathsDependsOn);
    BuildCustomConfig;
  </AssignTargetPathsDependsOn>
</PropertyGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="BuildCustomConfig">
  <TransformXml Source="MyCustom.config" Transform="MyCustom.$(Configuration).config" Destination="$(OutputPath)\MyCustom.config" />
  <ItemGroup>
    <Content Include="$(OutputPath)\MyCustom.config" Condition="Exists('$(OutputPath)\MyCustom.config')">
      <Link>MyCustom.config</Link>
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
</Target>