Search code examples
c#azureazure-devopsazure-pipelinesappsettings

How to setup devops for build-once, but for multiple environments


I am trying to improve our build/release process as work, but I have hit a snag, and I am not sure if it's because of trying to do the impossible, or just me not grasping some concepts.

As source we have a C# asp.net application with four appsettings-files for different environments. The appsettings are the default appsettings.json, appsettings.development.json, appsettings.test.json, and appsettings.release.json

Our environments are 'dev' which is a local developers PC, 'test' which is a test-server located onprem, and 'release' is also onprem but on a public-facing server. Later on the release-server will be in azure as a webapp. So it's nice to do this in a way that is compatible with Azure.

Ideally I want to have a build-once system where I build the code and generate artifacts, and just promote the artifacts from dev to test and finally release.

Is this a decent way to to this; I remove all appsettings files except appsettings.json, and add one build-pipeline to build it, and then make multiple release-pipelines, one pipeline per environment, each with a plethora of variables to configure the appsettings.json file to match the environment it will be deployed to?

Ideally I would like to keep the different appsettings files so all changes to the environments are configured there, but I realize that the way the appsettings files are manipulated on build means that won't work.

Hoping for some input so I can start setup this up. And thanks in advance.


Solution

  • Based on your requirement, you need to keep one appsettings.json file in the project and use multiple pipeline variables to configure the appsettings.json file based on the environment.

    This is a common situation in CI/CD deployments.

    To meet your requirement, I suggest that you can use the built-in task: File Transform task in each pipelines to replace the value in the Appsettings.json file.

    Here is an example:

    Appsettings.json

    {
      "Data": {
        "DefaultConnection": {
          "ConnectionString": "Data Source=(LocalDb)\\MSDB;AttachDbFilename=aspcore-local.mdf;"
        },
        "DebugMode": "enabled",
        "DBAccess": {
          "Administrators": ["Admin-1", "Admin-2"],
          "Users": ["Vendor-1", "vendor-3"]
        },
        "FeatureFlags": {
          "Preview": [
            {
              "newUI": "AllAccounts"
            },
            {
              "NewWelcomeMessage": "Newusers"
            }
          ]
        }
      }
    }
    

    Set the Pipeline variables and use File Transform task:

    variables:
      Data.DebugMode: disabled
      Data.DefaultConnection.ConnectionString: 'Data Source=(prodDB)\MSDB;AttachDbFilename=prod.mdf;'
      Data.DBAccess.Users.0: Admin-3
      Data.FeatureFlags.Preview.1.NewWelcomeMessage: AllAccounts
    
    # Update appsettings.json via FileTransform task.
    - task: FileTransform@2
      displayName: 'File transformation: appsettings.json'
      inputs:
        folderPath: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
        targetFiles: '**/appsettings.json'
        fileType: json
    

    For more detailed info, you can refer to this doc: JSON variable substitution