Applications of Web.config (App.config) in .NET Framework
Publishing Different Configuration Files for Different Build Configurations
Normally, Web.config (App.config) settings for local development, testing environments, and production environments are different. It is too cumbersome to manually change settings to match the environment every time you update the program. If you choose not to update the Web.config (App.config) during a program update, you might forget to adjust the configuration file content on the test/development environment when new settings are added or modified.
One approach is to overwrite the configuration file with every program update, but to generate the environment-specific configuration file during the publishing process.
Build Configurations
If you need to build a project based on different settings, you will need to set up Build Configurations. Different settings cover producing different configuration files, compilation options, or producing different compilation results based on different project constants. For details, please refer to "Understand build configurations".
The default build configurations are debug and release, which can be switched in the IDE.

Web Project Publishing
Regarding project publishing, this article only covers folder publishing. I have not explored other publishing methods. If needed, please refer to "Quickstart: Deploy an ASP.NET web app".
Adding a Publish Profile
Right-click the project and select "Publish".

Click "New publish profile".

This article only discusses folder publishing, so select "Folder".

Set the output folder. I am accustomed to setting it to
bin\Publish\{ConfigurationName}. Here, I set it tobin\Publish\Release.
After adding, it is recommended to rename the publish profile to match the configuration name or include a brief description.

Edit the publish settings. Basic settings can be edited via the UI. I check all of them here, but in practice, please adjust according to your needs. For example, if you are publishing to a website and set it to "Delete all existing files in the destination prior to publish," it will cause temporary files stored on the site (e.g., uploaded files) to be deleted as well.

You can directly modify the XML to change publish settings, for example, by adding
<ExcludeFilesFromDeployment>packages.config;Scripts\_references.js</ExcludeFilesFromDeployment>to exclude specific files during publishing. As for the specific publish settings available in XML, I have not found relevant documentation on MSDN.
TIP
When a publish profile is created, another file named "{Profile}.pubxml.user" is generated. The purpose of this file is unclear; it actually looks more like a publish log, which contradicts the description on MSDN. In any case, this file should not be included in version control. In fact, the default Visual Studio ".gitignore" also ignores user setting files with the ".user" extension.
Web.config Transform
When creating a new Web project, you will find three Config files in the project root by default: "Web.config", "Web.Debug.config", and "Web.Release.config". However, when building the project, you will find that the "Web.config" settings are always used. The other two Config files are actually used to transform parts of "Web.config" during publishing.
- If you find that a "Web.{ConfigurationName}.config" file corresponding to a build configuration is missing (possibly due to accidental deletion or creating a new build configuration), you can right-click on "Web.config" and select "Add Config Transform". After clicking, the missing Config file will be created.

- Right-click on "Web.{ConfigurationName}.config" and select "Preview Transform" to view the transformation results.

Transform replacement mechanism. Transform uses XML structure to locate content to be replaced. The
xdt:Transformattribute sets the replacement method. Let's use the following example content for explanation.xml<a> <b> <c> <e name="e1" value="v1"></e> <e name="e2" value="v2"></e> </c> <d></d> </b> </a>If you want to replace the content of the
<d>node, you need to prepare an XML containing the<d>node and all parent nodes, with the structure as follows:xml<a> <b> <d xdt:Transform="Replace"></d> </b> </a>For nodes like
<e>where there are multiple nodes with the same name under the same parent, you need to use thexdt:Locatorattribute to locate them. For example, if you want to replace<e name="e1"></e>, the XML content would be:xml<a> <b> <c> <e name="e1" value="v11" xdt:Locator="Match(name)" xdt:Transform="SetAttributes"></e> </c> </b> </a>Common transformation settings.
Replacing
connectionStrings.xml<!--Replace all connectionStrings--> <connectionStrings xdt:Transform="Replace"> <add name="Default" connectionString="{connectionString}" providerName="System.Data.SqlClient" /> </connectionStrings> <!--Replace only a single string--> <add name="Default" connectionString="{connectionString}" providerName="System.Data.SqlClient" xdt:Locator="Match(name)" xdt:Transform="SetAttributes" />Replacing
appSettings.xml<!--It is recommended to replace individually rather than replacing the entire appSettings--> <add key="key" value="value1" xdt:Locator="Match(key)" xdt:Transform="SetAttributes" />Common
system.webreplacement items.xml<!--Change mode="Off" to RemoteOnly, and add defaultRedirect --> <customErrors mode="RemoteOnly" xdt:Transform="SetAttributes" /> <!--Change enableVersionHeader to false--> <httpRuntime enableVersionHeader="false" xdt:Transform="SetAttributes(enableVersionHeader)" /> <!--Change requireSSL to true--> <httpCookies requireSSL="true" xdt:Transform="SetAttributes(requireSSL)" /> <!--Remove debug="true" setting--> <compilation xdt:Transform="RemoveAttributes(debug)" />
For the complete Transform syntax, please refer to "Web.config Transformation Syntax for Web Project Deployment Using Visual Studio".
Publishing
After selecting publish, you will see the output files in the target folder. At this point, you will find that the generated "Web.config" contains the merged content.

Example
Original Web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="MyDB" connectionString="Data Source=SQLServer;Initial Catalog=MyDB;Integrated Security=True" />
</connectionStrings>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="MyKey" value="MyValue" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.8.1" />
<customErrors mode="Off" />
<httpRuntime targetFramework="4.8.1" />
<httpCookies requireSSL="false" />
</system.web>
<!--Remaining parts are unchanged, omitted here-->
</configuration>Web.Release.config
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add name="MyDB" connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
</connectionStrings>
<appSettings>
<add key="MyKey" value="MyReleaseValue" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
</appSettings>
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
<customErrors mode="RemoteOnly" xdt:Transform="SetAttributes" />
<httpRuntime enableVersionHeader="false"
xdt:Transform="SetAttributes(enableVersionHeader)" />
<!--Change requireSSL to true-->
<httpCookies requireSSL="true"
xdt:Transform="SetAttributes(requireSSL)" />
</system.web>
</configuration>Published Web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="MyDB" connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True" />
</connectionStrings>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="MyKey" value="MyReleaseValue" />
</appSettings>
<system.web>
<compilation targetFramework="4.8.1" />
<customErrors mode="RemoteOnly" />
<httpRuntime targetFramework="4.8.1" enableVersionHeader="false" />
<httpCookies requireSSL="true" />
</system.web>
<runtime>
<!--Remaining parts are unchanged, omitted here-->
</configuration>Non-Web Project Publishing
Non-Web projects do not support "App.config" Transform by default, so you need to install other packages to handle it.
Packages
- Visual Studio: Install "SlowCheetah" in extensions.
- NuGet: Install "Microsoft.VisualStudio.SlowCheetah" on the project where you want to use Config Transform.
After installing "SlowCheetah" in Visual Studio, an "Add Transform" option will be added to the right-click menu of App.config in non-Web projects, allowing you to generate Config files for other configurations.

If "Microsoft.VisualStudio.SlowCheetah" is not installed via NuGet, it will prompt you and install it automatically.

TIP
Actually, Visual Studio has another extension called "ConfigTransformation" that supports Config Transform and does not require installing additional NuGet packages in the project. However, Visual Studio 2022 does not support this extension, and it can only perform transformations on XML with a complete Config structure (root node is <configuration />).
Build
Publishing for non-Web projects in ".NET Framework" uses ClickOnce and cannot be published to a folder like Web projects. However, its build will trigger Config Transform, so after selecting the configuration to publish, just build the project. It is recommended to delete the "bin" folder before building the project.

Example
Original App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="MyDB" connectionString="Data Source=SQLServer;Initial Catalog=MyDB;Integrated Security=True" />
</connectionStrings>
<appSettings>
<add key="MyKey" value="MyValue" />
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8.1" />
</startup>
</configuration>App.Release.config
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add name="MyDB" connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
</connectionStrings>
<appSettings>
<add key="MyKey" value="MyReleaseValue" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
</appSettings>
</configuration>Built {ProjectName}.exe.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="MyDB" connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True" />
</connectionStrings>
<appSettings>
<add key="MyKey" value="MyReleaseValue" />
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8.1" />
</startup>
</configuration>Sharing Configuration Files Across Different Projects
If multiple projects under the same solution need to connect to the same database, such as a website, multiple schedulers, or Web APIs, and every time the database environment changes, all projects need to be modified, you can consider placing <connectionStrings /> in a separate file to allow multiple projects to reference it.
Setup Steps
Create a Library project and add three configuration files: "AppGlobal.config", "Connection.config", and "Smtp.config". All three files are set up with Config Transform.
For convenience, these three files will be collectively referred to as external configuration files, and those produced by Config Transform will be referred to as external configuration settings files.

Setting Config Content
Here, we only use AppGlobal.config as an example.
AppGlobal.config
<?xml version="1.0" encoding="utf-8" ?>
<appSettings>
<add key="Test" value="TestValue1" />
</appSettings><?xml version="1.0" encoding="utf-8" ?>
<!--The root node must contain the attribute xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" -->
<appSettings xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<add key="Test" value="TestReleaseValue1" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
</appSettings>Adding References from a Web Project
- Install "Microsoft.VisualStudio.SlowCheetah" to handle the transformation of these external configuration files.
- In addition to adding the Library project reference to the Web project.
- You also need to add file links to the three newly created Config files and their related configuration files. Select "Add Existing Item" in the Web project.

Use the "Add as Link" method to add external configuration files and related external configuration settings files.

- Open the project file (csproj) and make the following modifications:
- Add
<TransformOnBuild>true</TransformOnBuild>to indicate that Config Transform should be executed during build. - Add
<CopyToOutputDirectory>Always</CopyToOutputDirectory>to external configuration files. - Change external configuration settings files from
<Content />nodes to<None />nodes to prevent them from being published as well. - Add
<DependentUpon />nodes to external configuration settings files so that they are displayed nested under the external configuration files in Visual Studio.
- Add
<Content Include="..\BuildConfigSample.Library\AppGlobal.config">
<Link>AppGlobal.config</Link>
<TransformOnBuild>true</TransformOnBuild>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<None Include="..\BuildConfigSample.Library\AppGlobal.Debug.config">
<Link>AppGlobal.Debug.config</Link>
<DependentUpon>AppGlobal.config</DependentUpon>
<TransformOnBuild>true</TransformOnBuild>
</None>
<None Include="..\BuildConfigSample.Library\AppGlobal.Release.config">
<Link>AppGlobal.Release.config</Link>
<DependentUpon>AppGlobal.config</DependentUpon>
<TransformOnBuild>true</TransformOnBuild>
</None>
<!--Connection.config and Smtp.config are modified in the same way-->- Modify "Web.config" and "Web.Release.config" to externally reference the external configuration files.
The difference between
configSourceandfileattributes is that the latter allows adding other settings for merging.<connectionStrings />and<smtp />cannot usefile.<appSettings />allows usingconfigSource, but it is recommended to usefile.If the
keyin the externally referenced file for<appSettings />is the same as akeyadded by yourself, the externally referenced value will be used, so you cannot override settings by defining the samekey.- Using the link method to add configuration files means there are no files in the project root, causing "Web.config" to be unable to find the external configuration file in the same folder when the Web is running in Debug mode. Therefore, reference the files under "bin" instead (during setup, we set the external configuration files to "Copy to Output Directory").
Web.config
xml<configuration> <connectionStrings configSource="bin\Connection.config" /> <appSettings file="bin\AppGlobal.config"> <add key="webpages:Version" value="3.0.0.0" /> <add key="webpages:Enabled" value="false" /> <add key="ClientValidationEnabled" value="true" /> <add key="UnobtrusiveJavaScriptEnabled" value="true" /> <add key="MyKey" value="MyValue" /> </appSettings> <system.net> <mailSettings> <smtp configSource="bin\Smtp.config" /> </mailSettings> </system.net> <!--Remaining content omitted--> </configuration>Web.Release.config
xml<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <connectionStrings configSource="Connection.config" xdt:Transform="SetAttributes" /> <appSettings file="AppGlobal.config" xdt:Transform="SetAttributes"> <add key="MyKey" value="MyReleaseValue" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" /> </appSettings> <system.net> <mailSettings> <smtp configSource="Smtp.config" xdt:Transform="Replace" /> </mailSettings> </system.net> <!--Remaining content omitted--> </configuration>
Adding References from a Non-Web Project
The previous operation steps are the same as for Web projects, but the modifications to the project file and App.config content are slightly different.
The external configuration files in the project file use <None /> nodes.
<None Include="..\BuildConfigSample.Library\AppGlobal.config">
<Link>AppGlobal.config</Link>
<TransformOnBuild>true</TransformOnBuild>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\BuildConfigSample.Library\AppGlobal.Debug.config">
<Link>AppGlobal.Debug.config</Link>
<DependentUpon>AppGlobal.config</DependentUpon>
<TransformOnBuild>true</TransformOnBuild>
</None>
<None Include="..\BuildConfigSample.Library\AppGlobal.Release.config">
<Link>AppGlobal.Release.config</Link>
<DependentUpon>AppGlobal.config</DependentUpon>
<TransformOnBuild>true</TransformOnBuild>
</None>TIP
The <None /> node and <Content /> node correspond to the build actions "None" and "Content" respectively. "Content" is for Web use. For details, please refer to "Build action values".
App.config
Because in Debug mode, the configuration file itself uses the "{ProjectName}.exe.config" file under "bin{ConfigurationName}", the path does not need to be specified under "bin".
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings configSource="Connection.config" />
<appSettings file="AppGlobal.config">
<add key="MyKey" value="MyValue" />
</appSettings>
<system.net>
<mailSettings>
<smtp configSource="Smtp.config" />
</mailSettings>
</system.net>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8.1" />
</startup>
</configuration>App.Release.config
After changing to external referencing, App.Release.config no longer needs to transform the connectionStrings content.
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add key="MyKey" value="MyReleaseValue" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
</appSettings>
</configuration>WARNING
If you are using Entity Framework's Database First, the connection string in the project's App.config cannot be set using an external reference file, otherwise the Entity Framework UI will not be able to find the already configured connection string.
Breaking the Inheritance Relationship of Web.config
IIS allows building sub-websites under a website. In this case, the sub-website's Web.config will inherit the parent website's settings. Sometimes conflicts occur, especially when there is a difference in Framework versions between the two. In this case, you can use <location> in the parent website to break the inheritance. The syntax is as follows:
<location path="." inheritInChildApplications="false">
<system.web>
<!--...Internal code...-->
</system.web>
</location>TIP
Theoretically, writing <location /> outside of <system.web /> is sufficient, but if necessary, it can also be added outside other nodes. However, if the project uses Entity Framework's Database First, do not write it outside the <connectionStrings /> layer, otherwise it will cause the Entity Framework UI to be unable to read the configured connection string (this problem again, orz).
Related Links
Change Log
- 2022-11-10 Initial version of the document created.