Skip to content
No description, website, or topics provided.
C# PowerShell Shell Batchfile
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
build
scripts
src/Pivotal.Web.Config.Transform.Buildpack
tests
.gitattributes
.gitignore
.nuke
README.md
Web.Config.Transform.Buildpack.sln
build.ps1
build.sh
nuget.config

README.md

Web Config Transform Buildpack

Purpose of the web-config-transform-buildpack

Cloud Native Applications are expected to bring in configurations from external sources like environment variables, config server, etc. Please refer to Configuration in 12factor.net for more information.

In legacy ASP.Net applications, configuration settings are injected through Web.config files. As per cloud native principles, configuration should stay out of build artifacts. In this recipe we will use a custom buildpack which provides a solution to this problem by using token replacement during cf push staging.

High level steps

  1. Identify environment dependent configurations and externalize
  2. Create app manifest
  3. Add web config transformations
  4. Move config settings to Spring Cloud Config Server
  5. Create service for Spring Cloud Config Server
  6. Bind config service to app using manifest
  7. Push app by parameterized environment name

1. Identify environment dependent configurations and externalize

  • Identify configuration items (in Web.config files) that are environment dependent that need to be externalized.
  • Modify your transform file (ex: Web.Release.config) to use tokenized configuration items in the following format #{configPath:key}. For e.g. please refer before and after as below

    Note: all transform xml attributes and tokens are case-sensitive

Before tokenizing

Web.Config

<connectionStrings>
    <add name="MyDB" 
         connectionString="Data Source=LocalSQLServer;Initial Catalog=MyReleaseDB;User ID=xxxx;Password=xxxx" />
</connectionStrings>

Web.Release.config

<connectionStrings>
    <add name="MyDB" 
         connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;User ID=xxxx;Password=xxxx" 
         xdt:Transform="SetAttributes" 
         xdt:Locator="Match(name)"/>
</connectionStrings>
After tokenizing

Web.Config (no change)

Web.Release.config

<connectionStrings>
    <add name="MyDB" 
         connectionString="#{connectionStrings:MyDB}" 
         xdt:Transform="SetAttributes" 
         xdt:Locator="Match(name)"/>
</connectionStrings>

2. Create a Cloud Foundry app manifest

  • Ensure your application has a Cloud Foundry manifest file. If your application is in Cloud Foundry already, you can create the manifest using the command cf create-app-manifest [appname].
  • Add a buildpack reference to the manifest (before the hwc buildpack) that will perform the token replacement on cf push action.

    Note: Please refer to https://github.com/cloudfoundry-community/web-config-transform-buildpack/releases to pull the latest version as appropriate. XXX refers to the version of buildpack.

  • Add an environment variable to the manifest for each config item that will be used to replace the tokenized values. Below is a sample added referring to the connection string.

    Note: Adding token replacements with Environment variables is only for experimental activities. Config settings should be externalized using git repositories and Spring Cloud Config Server.

applications:
- name: sampleapp
  stack: windows
  buildpacks:
  - https://github.com/cloudfoundry-community/web-config-transform-buildpack/releases/download/vXXX/Web.Config.Transform.Buildpack-win-x64-XXX.zip
  - hwc_buildpack
  env:
    "connectionStrings:MyDB": "Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;User ID=xxxx;Password=xxxx"
Note

Only put configuration item keys and values in the manifest for testing purposes. Spring Cloud Config Server should be used for externalizing configuration settings (see further sections).

3. Add web config transformations

By default, all web apps and wcf apps created with Debug and Release configurations and corresponding web config transformation files (Web.Debug.config, Web.Release.config).

  • Add required transformations to Web.Release.Config

  • Build and push the application to Cloud Foundry to verify that your config settings are properly transformed

Note

For developer machine debugging, use Debug configuration profile and Web.Debug.config for transformation.

Sample Web.Release.Config with transformations

<?xml version="1.0" encoding="utf-8"?>
<!-- For Cloud Foundry -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  
  <connectionStrings  xdt:Transform="Replace">
    <add name="MyDB" connectionString="#{connectionStrings:MyDB}" providerName="System.Data.SqlClient"/>
  </connectionStrings>
  
  <system.serviceModel>
    <client xdt:Transform="Replace">
      
      <endpoint 
        address="#{client:Default_IMyLogService:address}" 
        binding="#{client:Default_IMyLogService:binding}" 
        bindingConfiguration="#{client:Default_IMyLogService:bindingConfiguration}"
        contract="ServiceProxy.IMyLogService" name="Default_IMyLogService" />
    
    </client>
  </system.serviceModel>

</configuration>

4. Move config settings to Spring Cloud Config Server

A multi-environment, production-ready configuration can be achieved using share and environment specific transforms and using Spring Cloud Config Server - backed by a git repository data source.

  1. Create a network accessible git repository for each application
  2. Create <YOUR_APPLICATION>.yaml file to have common settings across all environments
  3. Create <YOUR_APPLICATION>-< YOUR_APP_ENVIRONMENT>.yaml for each unique environment
  4. Specify your environment with ASPNETCORE_ENVIRONMENT environment variable in the manifest file created in step 2. e.g: ASPNETCORE_ENVIRONMENT=Production
Sample Config Server yml files

sampleapp.yaml

appSettings:
  Setting1: "Common setting1"

sampleapp-Development.yaml

 connectionStrings:
   MyDB: "Data Source=devserver;Initial Catalog=mydb;User ID=xxxx;Password=xxxx"

sampleapp-Production.yaml

 connectionStrings:
   MyDB: "Data Source=prodserver;Initial Catalog=mydb;User ID=xxxx;Password=xxxx"

5. Create service for Spring Cloud Config Server

  1. Make sure you have config server available in your CF marketplace.

    NOTE: To check if you have this server, run cf marketplace. You should see p.config-server or p-config-server in this list.

  2. Create a JSON file for config server setup (ex: config-server.json)

    {
        "git" : { 
            "uri": "https://github.com/YOUR_USERNAME/YOUR_CONFIG_REPO"
        }
    
    }

    NOTE: Ensure file is not BOM-encoded

  3. Create config server using above configuration file.

    cf create-service p-config-server standard my_configserver  -c .\config-server.json
    

6. Bind config service to app using manifest

Bind the config server to your app once the config server service is created. Add your config server to the services section as seen below:

---
applications:
- name: sampleapp
  stack: windows
  buildpacks: 
    - https://github.com/cloudfoundry-community/web-config-transform-buildpack/releases/download/vXXX/Web.Config.Transform.Buildpack-win-x64-1.1.5.zip
    - hwc_buildpack
  env:
    ASPNETCORE_ENVIRONMENT: ((env))

  services:
  - my_configserver

7. Push app by parameterized environment name

Parameterizing your application environment gives ability to provide different value as per you deploy stage in CD pipelines. e.g: Development/QA/UAT/Production.

This can be achieved by replacing hardcoded value of ASPNETCORE_ENVIRONMENT=YOUR_DEPLOY_ENVIRONMENT with ASPNETCORE_ENVIRONMENT: ((env))

Now you can push your app with below command

cf push --var env=Production

You should be able to find if the environment value is actually passed in, by looking at logs.

================================================================================
=============== WebConfig Transform Buildpack execution started ================
================================================================================
-----> Using Environment: Production
-----> Config server binding found...

Special Behavior for appSettings and connectionStrings

This buildpack makes it possible to externalize appSettings and connectionString values in your Web.config without using tokenized values. In this case simply include the values in your yaml config files on your Github repository ({YOUR-APP}.production.yml, YOUR-APP}.development.yml, etc.

sampleapp-Development.yaml

appSettings:
  Setting1: "development setting"
 connectionStrings:
   MyDB: "Data Source=devserver;Initial Catalog=mydb;User ID=xxxx;Password=xxxx"

sampleapp-Production.yaml

appSettings:
  Setting1: "production setting"
 connectionStrings:
   MyDB: "Data Source=prodserver;Initial Catalog=mydb;User ID=xxxx;Password=xxxx"

This buildpack can inject appSettings and connectionStrings values based on environment specific yaml config files even if replacement tokens are not present in Web.Release.Config file.

Sample Application & Walkthrough

A sample web application and walkthrough can be found here

Note

For any issues you face with the web-config-transform-buildpack, please raise an issue at https://github.com/cloudfoundry-community/web-config-transform-buildpack/issues.

You can’t perform that action at this time.