【问题标题】:how to write a task that performs appSettings.json transforms using MSBuild?如何编写使用 MSBuild 执行 appSettings.json 转换的任务?
【发布时间】:2017-11-30 15:42:55
【问题描述】:

我有一个 ASP .NET Core 应用程序,我想将它部署到 2 个不同的环境:1) 暂存,2) 生产。我的项目中有以下包含数据库连接字符串的文件:

appSettings.json
appSettings.staging.json
appSettings.production.json

可以说,connectionString 的名称是“MyDb”。如果为生产运行构建,我希望能够将 appSettings.json 中的 MyDb 的值替换为 appSettings.production.json 中的值,如果为暂存运行构建,则使用 appSettings.staging.json 替换。

我该怎么做?一步一步的例子会很棒。

【问题讨论】:

    标签: visual-studio msbuild web-deployment


    【解决方案1】:

    如何编写一个使用 MSBuild 执行 appSettings.json 转换的任务?

    您可以在项目文件中添加自定义任务ReplaceFileText

    要完成此操作,请卸载您的项目。然后在项目的最后,就在结束标记 </Project> 之前,放置以下脚本:

    <UsingTask TaskName="ReplaceFileText" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
        <ParameterGroup>
          <InputFilename ParameterType="System.String" Required="true" />
          <OutputFilename ParameterType="System.String" Required="true" />
          <MatchExpression ParameterType="System.String" Required="true" />
          <ReplacementText ParameterType="System.String" Required="true" />
        </ParameterGroup>
        <Task>
          <Reference Include="System.Core" />
          <Using Namespace="System" />
          <Using Namespace="System.IO" />
          <Using Namespace="System.Text.RegularExpressions" />
          <Code Type="Fragment" Language="cs">
            <![CDATA[
                File.WriteAllText(
                    OutputFilename,
                    Regex.Replace(File.ReadAllText(InputFilename), MatchExpression, ReplacementText)
                    );
              ]]>
          </Code>
        </Task>
      </UsingTask>
    
      <Target Name="TransformsWithProduction" Condition="'$(Configuration)'=='Production'" AfterTargets="Build"> 
        <ReplaceFileText
          InputFilename="$(ProjectDir)appsettings.json"
          OutputFilename="$(ProjectDir)appsettings.json"
          MatchExpression="MyDb"
          ReplacementText="MyDbProduction" />
      </Target>
    
      <Target Name="TransformsWithProduction" Condition="'$(Configuration)'=='staging'" AfterTargets="Build">
        <ReplaceFileText
          InputFilename="$(ProjectDir)appsettings.json"
          OutputFilename="$(ProjectDir)appsettings.json"
          MatchExpression="MyDb"
          ReplacementText="MyDbstaging" />
      </Target>
    

    以上示例将文件appSettings.json中的“MyDb”替换为“MyDbstaging”或“MyDbProduction”。

    此外,为了能够重复使用此任务,而无需在每次修改后手动将 appSettings.json 文件中的值恢复为“MyDb”,我们可以添加另一个任务来恢复此值:

      <Target Name="RestoreJsonFile" BeforeTargets="Build">
        <Copy
                SourceFiles="$(ProjectDir)\BackupJsonFile\appsettings.json"
                DestinationFolder="$(ProjectDir)"
            />
      </Target>
    

    在备份文件夹BackupJsonFile中备份那个appSettings.json,然后复制它以替换已修改的那个。

    所以最终的自定义任务应该是:

     <UsingTask TaskName="ReplaceFileText" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
        <ParameterGroup>
          <InputFilename ParameterType="System.String" Required="true" />
          <OutputFilename ParameterType="System.String" Required="true" />
          <MatchExpression ParameterType="System.String" Required="true" />
          <ReplacementText ParameterType="System.String" Required="true" />
        </ParameterGroup>
        <Task>
          <Reference Include="System.Core" />
          <Using Namespace="System" />
          <Using Namespace="System.IO" />
          <Using Namespace="System.Text.RegularExpressions" />
          <Code Type="Fragment" Language="cs">
            <![CDATA[
                File.WriteAllText(
                    OutputFilename,
                    Regex.Replace(File.ReadAllText(InputFilename), MatchExpression, ReplacementText)
                    );
              ]]>
          </Code>
        </Task>
      </UsingTask>
    
      <Target Name="RestoreJsonFile" BeforeTargets="Build">
        <Copy
                SourceFiles="$(ProjectDir)\BackupJsonFile\appsettings.json"
                DestinationFolder="$(ProjectDir)"
            />
      </Target>
    
      <Target Name="TransformsWithProduction" Condition="'$(Configuration)'=='Production'" AfterTargets="RestoreJsonFile"> 
        <ReplaceFileText
          InputFilename="$(ProjectDir)appsettings.json"
          OutputFilename="$(ProjectDir)appsettings.json"
          MatchExpression="MyDb"
          ReplacementText="MyDbProduction" />
      </Target>
    
      <Target Name="TransformsWithstaging" Condition="'$(Configuration)'=='staging'" AfterTargets="RestoreJsonFile">
        <ReplaceFileText
          InputFilename="$(ProjectDir)appsettings.json"
          OutputFilename="$(ProjectDir)appsettings.json"
          MatchExpression="MyDb"
          ReplacementText="MyDbstaging" />
      </Target>
    

    顺便说一句,如果替换 appSettings.json 中的 MyDb 的值不是您唯一的选择,如果为生产运行构建,您可以尝试使用 appSettings.production.json,而不是替换 appSettings.json 中的值。请参阅Config transformations in ASP.NET CoreAppsettings.json configuration in ASP.Net Core Web API 更多详细信息。

    希望这会有所帮助。

    【讨论】:

    • 按照上述步骤后,我将活动解决方案配置更改为“生产”并构建了项目,并且在 appSettings.json 文件中没有看到任何变化。
    • @Dev_Net,这是我的错。我用TransformsWithProduction复制了目标名称,现在我更新了它,你可以检查它,我已经测试过它,它工作正常。
    • 感谢 Leo,这没有任何问题。有几件事:1)如何将 appSettings.json 中名为“connectionStrings”的整个部分替换为 appSettings.Production.json 或 appSettings.Staging.json 中的相同部分? 2)只有在我必须发布代码而不是在每个构建时才可以运行这些构建任务吗?
    • @Dev_Net,对于问题 1),是的,您可以。只需将双引号替换为&amp;quot;。对于第二个,恐怕不会。因为条件是'$(Configuration)'=='Production',所以这个值不能传递给发布进程,只能被构建进程支持。
    • 感谢您的帮助:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-27
    • 1970-01-01
    • 2011-08-27
    相关资源
    最近更新 更多