Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to write a task that performs appSettings.json transforms using MSBuild?

I have a ASP .NET Core application that I want to deploy to 2 different environments: 1) Staging, 2) Production. I have the following files in my project that contains database connectionStrings:

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

lets say, the name of connectionString is "MyDb". I want the ability to replace the value of MyDb in appSettings.json with one in appSettings.production.json if the build is run for Production and with appSettings.staging.json if the build is run for staging.

How can I do that? A step by step example would be great.

like image 384
Farooq Hanif Avatar asked Sep 10 '26 10:09

Farooq Hanif


1 Answers

how to write a task that performs appSettings.json transforms using MSBuild?

You can add a custom task ReplaceFileText into the project file.

To accomplish this, unload your project. Then at the very end of the project, just before the end-tag </Project>, place below scripts:

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

The above example replaces "MyDb" with "MyDbstaging" or "MyDbProduction" in the file appSettings.json.

Besides, in order to be able to re-use this task without the need to manually restore the value to "MyDb" in the appSettings.json file after each modification, we could add a another task to restore this value:

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

Back up that appSettings.json in the back up folder BackupJsonFile, then copy it to replace the one that has been modified.

So the final custom task should be:

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

enter image description here

BTW, if replace the value of MyDb in appSettings.json is not your only option, you can try to use appSettings.production.json if the build is run for Production instead of replacing the value in appSettings.json. See Config transformations in ASP.NET Core and Appsettings.json configuration in ASP.Net Core Web API more detailed info.

Hope this helps.

like image 87
Leo Liu-MSFT Avatar answered Sep 12 '26 16:09

Leo Liu-MSFT