ASP.NET Web Deployment using Visual Studio: Web.config File Transformations
by Tom Dykstra
This tutorial series shows you how to deploy (publish) an ASP.NET web application to Azure App Service Web Apps or to a third-party hosting provider, by using Visual Studio 2012 or Visual Studio 2010. For information about the series, see the first tutorial in the series.
This tutorial shows you how to automate the process of changing the Web.config file when you deploy it to different destination environments. Most applications have settings in the Web.config file that must be different when the application is deployed. Automating the process of making these changes keeps you from having to do them manually every time you deploy, which would be tedious and error prone.
Reminder: If you get an error message or something doesn't work as you go through the tutorial, be sure to check the troubleshooting page.
Web.config transformations versus Web Deploy parameters
There are two ways to automate the process of changing Web.config file settings: Web.config transformations and Web Deploy parameters. A Web.config transformation file contains XML markup that specifies how to change the Web.config file when it is deployed. You can specify different changes for specific build configurations and for specific publish profiles. The default build configurations are Debug and Release, and you can create custom build configurations. A publish profile typically corresponds to a destination environment. (You'll learn more about publish profiles in the Deploying to IIS as a Test Environment tutorial.)
Web Deploy parameters can be used to specify many different kinds of settings that must be configured during deployment, including settings that are found in Web.config files. When used to specify Web.config file changes, Web Deploy parameters are more complex to set up, but they are useful when you do not know the value to be set until you deploy. For example, in an enterprise environment, you might create a deployment package and give it to a person in the IT department to install in production, and that person has to be able to enter connection strings or passwords that you do not know.
For the scenario that this tutorial series covers, you know in advance everything that has to be done to the Web.config file, so you do not need to use Web Deploy parameters. You'll configure some transformations that differ depending on the build configuration used, and some that differ depending on the publish profile used.
Specifying Web.config settings in Azure
If the Web.config file settings that you want to change are in the
<connectionStrings> or the
<appSettings> element, and if you are deploying to Web Apps in Azure App Service, you have another option for automating changes during deployment. You can enter the settings that you want to take effect in Azure in the Configure tab of the management portal page for your web app (scroll down to the app settings and connection strings sections). When you deploy the project, Azure automatically applies the changes. For more information, see Windows Azure Web Sites: How Application Strings and Connection Strings Work.
Default transformation files
In Solution Explorer, expand Web.config to see the Web.Debug.config and Web.Release.config transformation files that are created by default for the two default build configurations.
You can create transformation files for custom build configurations by right-clicking the Web.config file and choosing Add Config Transforms from the context menu. For this tutorial you don't need to do that, and the menu option is disabled, because you haven't created any custom build configurations.
Later you'll create three more transformation files, one each for the test, staging, and production publish profiles. A typical example of a setting that you would handle in a publish profile transformation file because it depends on the destination environment is a WCF endpoint that is different for test versus production. You'll create publish profile transformation files in later tutorials after you create the publish profiles that they go with.
Disable debug mode
An example of a setting that depends on build configuration rather than destination environment is the
debug attribute. For a Release build, you typically want debugging disabled regardless of which environment you are deploying to. Therefore, by default the Visual Studio project templates create Web.Release.config transform files with code that removes the
debug attribute from the
compilation element. Here is the default Web.Release.config: in addition to some sample transformation code that is commented out, it includes code in the
compilation element that removes the
<?xml version="1.0" encoding="utf-8"?> <!-- For more information on using web.config transformation visit https://go.microsoft.com/fwlink/?LinkId=125889 --> <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <!-- In the example below, the "SetAttributes" transform will change the value of "connectionString" to use "ReleaseSQLServer" only when the "Match" locator finds an attribute "name" that has a value of "MyDB". <connectionStrings> <add name="MyDB" connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True" xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/> </connectionStrings> --> <system.web> <compilation xdt:Transform="RemoveAttributes(debug)" /> <!-- In the example below, the "Replace" transform will replace the entire <customErrors> section of your web.config file. Note that because there is only one customErrors section under the <system.web> node, there is no need to use the "xdt:Locator" attribute. <customErrors defaultRedirect="GenericError.htm" mode="RemoteOnly" xdt:Transform="Replace"> <error statusCode="500" redirect="InternalError.htm"/> </customErrors> --> </system.web> </configuration>
xdt:Transform="RemoveAttributes(debug)" attribute specifies that you want the
debug attribute to be removed from the
system.web/compilation element in the deployed Web.config file. This will be done every time you deploy a Release build.
Limit error log access to administrators
If there's an error while the application runs, the application displays a generic error page in place of the system-generated error page, and it uses the Elmah NuGet package for error logging and reporting. The
customErrors element in the application Web.config file specifies the error page:
<customErrors mode="RemoteOnly" defaultRedirect="~/GenericErrorPage.aspx"> <error statusCode="404" redirect="~/GenericErrorPage.aspx" /> </customErrors>
To see the error page, temporarily change the
mode attribute of the
customErrors element from "RemoteOnly" to "On" and run the application from Visual Studio. Cause an error by requesting an invalid URL, such as Studentsxxx.aspx. Instead of an IIS-generated "The resource cannot be found" error page, you see the GenericErrorPage.aspx page.
To see the error log, replace everything in the URL after the port number with elmah.axd (for example,
http://localhost:51130/elmah.axd) and press Enter:
Don't forget to set the
customErrors element back to "RemoteOnly" mode when you're done.
On your development computer it's convenient to allow free access to the error log page, but in production that would be a security risk. For the production site, you want to add an authorization rule that restricts error log access to administrators, and to make sure that the restriction works you want it in test and staging also. Therefore this is another change that you want to implement every time you deploy a Release build, and so it belongs in the Web.Release.config file.
Open Web.Release.config and add a new
location element immediately before the closing
configuration tag, as shown here.
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"> <!-- In the example below, the "SetAttributes" transform will change the value of "connectionString" to use "ReleaseSQLServer" only when the "Match" locator finds an attribute "name" that has a value of "MyDB". <connectionStrings> <add name="MyDB" connectionString="Data Source=ReleaseSQLServer;Initial Catalog=MyReleaseDB;Integrated Security=True" xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/> </connectionStrings> --> <system.web> <compilation xdt:Transform="RemoveAttributes(debug)" /> <!-- In the example below, the "Replace" transform will replace the entire <customErrors> section of your web.config file. Note that because there is only one customErrors section under the <system.web> node, there is no need to use the "xdt:Locator" attribute. <customErrors defaultRedirect="GenericError.htm" mode="RemoteOnly" xdt:Transform="Replace"> <error statusCode="500" redirect="InternalError.htm"/> </customErrors> --> </system.web> <location path="elmah.axd" xdt:Transform="Insert"> <system.web> <authorization> <allow roles="Administrator" /> <deny users="*" /> </authorization> </system.web> </location> </configuration>
Transform attribute value of "Insert" causes this
location element to be added as a sibling to any existing
location elements in the Web.config file. (There is already one
location element that specifies authorization rules for the Update Credits page.)
Now you can preview the transform to make sure that you coded it correctly.
In Solution Explorer, right-click Web.Release.config and click Preview Transform.
A page opens that shows you the development Web.config file on the left and what the deployed Web.config file will look like on the right, with changes highlighted.
( In the preview, you might notice some additional changes that you didn't write transforms for: these typically involve the removal of white space that doesn't affect functionality.)
When you test the site after deployment, you'll also test to verify that the authorization rule is effective.
Security Note Never display error details to the public in a production application, or store that information in a public location. Attackers can use error information to discover vulnerabilities in a site. If you use ELMAH in your own application, configure ELMAH to minimize security risks. The ELMAH example in this tutorial should not be considered a recommended configuration. It is an example that was chosen in order to illustrate how to handle a folder that the application must be able to create files in. For more information, see securing the ELMAH endpoint.
A setting that you'll handle in publish profile transformation files
A common scenario is to have Web.config file settings that must be different in each environment that you deploy to. For example, an application that calls a WCF service might need a different endpoint in test and production environments. The Contoso University application includes a setting of this kind also. This setting controls a visible indicator on a site's pages that tells you which environment you are in, such as development, test, or production. The setting value determines whether the application will append "(Dev)" or "(Test)" to the main heading in the Site.Master master page:
The environment indicator is omitted when the application is running in staging or production.
The Contoso University web pages read a value that is set in
appSettings in the Web.config file in order to determine what environment the application is running in:
<appSettings> <add key="Environment" value="Dev" /> </appSettings>
The value should be "Test" in the test environment, and "Prod" for staging and production.
The following code in a transform file will implement this transformation:
<appSettings> <add key="Environment" value="Test" xdt:Transform="SetAttributes" xdt:Locator="Match(key)"/> </appSettings>
xdt:Transform attribute value "SetAttributes" indicates that the purpose of this transform is to change attribute values of an existing element in the Web.config file. The
xdt:Locator attribute value "Match(key)" indicates that the element to be modified is the one whose
key attribute matches the
key attribute specified here. The only other attribute of the
add element is
value, and that is what will be changed in the deployed Web.config file. The code shown here causes the
value attribute of the
appSettings element to be set to "Test" in the Web.config file that is deployed.
This transform belongs in the publish profile transform files, which you haven't created yet. You'll create and update the transform files that implement this change when you create the publish profiles for the test, staging, and production environments. You'll do that in the deploy to IIS and deploy to production tutorials.
Because this setting is in the
<appSettings> element, you have another alternative for specifying the transformation when you're deploying to Web Apps in Azure App Service See Specifying Web.config settings in Azure earlier in this topic.
Setting connection strings
Although the default transform file contains an example that shows how to update a connection string, in most cases you do not need to set up connection string transformations, because you can specify connection strings in the publish profile. You'll do that in the deploy to IIS and deploy to production tutorials.
You have now done as much as you can with Web.config transformations before you create the publish profiles, and you've seen a preview of what will be in the deployed Web.config file.
In the following tutorial, you'll take care of deployment set-up tasks that require setting project properties.
For more information about topics covered by this tutorial, see Using Web.config transformations to change settings in the destination Web.config file or app.config file during deployment in the Web Deployment Content Map for Visual Studio and ASP.NET.