Web.config
Web.config is the control panel of an MVC 5 app: database connections, feature switches, security settings and IIS behaviour all live in this one XML file.
On this page · 6 min · Advanced
On this page
- Learning objectives
- Explanation
- Syntax
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 6 min
- Difficulty
- Advanced
- Updated
- Oct 29, 2026
Related tutorials
Learning objectives#
- Store and read settings and connection strings
- Wrap settings in a typed class
- Keep secrets out of source control with an external file
- Change settings per environment with config transforms
Explanation#
<appSettings> holds key–value pairs read with ConfigurationManager.AppSettings["Key"] — always strings, so convert them. <connectionStrings> holds database connections read with ConfigurationManager.ConnectionStrings["Name"].
Wrap settings in a small class (AppSettings.FreeDeliveryOver) that parses and validates them once, so the rest of the code never sees raw strings or misspelled keys.
<appSettings file="secrets.config"> merges an extra file over the main settings. Keep secrets.config out of source control and create it on each server — or let Azure App Service settings override appSettings at runtime.
Config transforms (Web.Debug.config, Web.Release.config) change values when you publish: xdt:Transform="SetAttributes" with xdt:Locator="Match(key)" replaces a value; xdt:Transform="RemoveAttributes(debug)" removes debug="true".
Changing Web.config on a live server restarts the application (and clears InProc session). Plan changes for quiet times.
Syntax#
<appSettings file="secrets.config">
<add key="Shop:FreeDeliveryOver" value="500" />
</appSettings>
<connectionStrings>
<add name="ShopDb" connectionString="Server=.;Database=Shop;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
Code example: Typed settings, a secrets file and a release transform#
<!-- Web.config -->
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="ShopDb" connectionString="Server=(localdb)\mssqllocaldb;Database=ShopMvc5;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
<appSettings file="secrets.config">
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="Shop:Name" value="Techie Stationers" />
<add key="Shop:FreeDeliveryOver" value="500" />
<add key="Features:GiftCards" value="false" />
<add key="Payments:ApiKey" value="set-in-secrets.config" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.8" />
<httpRuntime targetFramework="4.8" maxRequestLength="10240" />
<customErrors mode="RemoteOnly" />
</system.web>
</configuration>
<!-- secrets.config -->
<appSettings>
<add key="Payments:ApiKey" value="sk_test_51Hx9" />
</appSettings>
<!-- Web.Release.config -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add key="Features:GiftCards" value="true" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
</appSettings>
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
<customErrors mode="On" xdt:Transform="SetAttributes" />
</system.web>
</configuration>
// App_Start/AppSettings.cs
using System;
using System.Configuration;
namespace ShopSite
{
public static class AppSettings
{
public static string ShopName => Read("Shop:Name");
public static decimal FreeDeliveryOver => decimal.Parse(Read("Shop:FreeDeliveryOver"));
public static bool GiftCardsEnabled => bool.Parse(Read("Features:GiftCards"));
public static string PaymentsKey => Read("Payments:ApiKey");
private static string Read(string key)
{
var value = ConfigurationManager.AppSettings[key];
if (string.IsNullOrWhiteSpace(value))
throw new ConfigurationErrorsException(quot;Missing app setting '{key}'");
return value;
}
}
}
// Controllers/SettingsController.cs
using System.Configuration;
using System.Web.Configuration;
using System.Web.Mvc;
namespace ShopSite.Controllers
{
public class SettingsController : Controller
{
public ActionResult Index()
{
var db = ConfigurationManager.ConnectionStrings["ShopDb"];
var runtime = (HttpRuntimeSection)ConfigurationManager.GetSection("system.web/httpRuntime");
return Content(
quot;Shop: {AppSettings.ShopName}\n" +
quot;Free delivery over: {AppSettings.FreeDeliveryOver:0}\n" +
quot;Gift cards enabled: {AppSettings.GiftCardsEnabled}\n" +
quot;Payments key: {AppSettings.PaymentsKey.Substring(0, 7)}… (from secrets.config)\n" +
quot;Database provider: {db.ProviderName}\n" +
quot;Max request: {runtime.MaxRequestLength} KB\n" +
quot;Debug compilation: {HttpContext.IsDebuggingEnabled}",
"text/plain");
}
}
}
GET /Settings 200 OK Shop: Techie Stationers Free delivery over: 500 Gift cards enabled: False Payments key: sk_test… (from secrets.config) Database provider: System.Data.SqlClient Max request: 10240 KB Debug compilation: True
This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.
Step-by-step explanation#
- AppSettings reads each key once through ConfigurationManager and converts it to the right type, throwing a clear error if a key is missing.
- Payments:ApiKey is defined in Web.config as a placeholder, but secrets.config (merged through file="…") overrides it with the real value.
- The connection string and httpRuntime values come from their own sections.
- Locally, debug compilation is on and gift cards are off. When you publish in Release, Web.Release.config turns gift cards on, removes debug="true" and switches customErrors to On.
Real-world use case#
A retailer runs the same MVC 5 app for three countries. Each server has its own secrets.config with payment keys and a transform sets the currency and tax settings, so the code and the main Web.config are identical everywhere.
Common mistakes#
Connection strings with passwords and API keys in Git are leaked with every clone. Use a secrets file, environment-specific transforms built on the server, or App Service settings.
Debug compilation disables batching and optimisations and makes errors more verbose. The Release transform should remove it.
ConfigurationManager.AppSettings["FreeDelivery"] scattered across the code breaks silently on a typo. Centralise keys in one class.
Best practices#
- Group keys with prefixes like Shop: and Features:
- Validate settings at startup
- Keep secrets out of source control
- Use transforms or deployment settings per environment
Remember this#
AppSettings = strings; convert them once.
file="secrets.config" overrides keys locally.
Web.Release.config transforms on publish.
Practice exercise#
Your task: Add a Shop:SupportEmail setting and show it on a contact page through the AppSettings class, failing clearly when it is missing.
Need a hint?
Show solution
<!-- Web.config -->
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="Shop:SupportEmail" value="help@techie-stationers.example" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.8" />
<httpRuntime targetFramework="4.8" />
</system.web>
</configuration>
// Controllers/ContactController.cs
using System.Configuration;
using System.Web.Mvc;
namespace ShopSite.Controllers
{
public class ContactController : Controller
{
public ActionResult Index()
{
var email = ConfigurationManager.AppSettings["Shop:SupportEmail"];
if (string.IsNullOrWhiteSpace(email)) throw new ConfigurationErrorsException("Missing Shop:SupportEmail");
return Content("Write to us: " + email, "text/plain");
}
}
}
GET /Contact 200 OK Write to us: help@techie-stationers.example
Mini quiz#
What type does ConfigurationManager.AppSettings["Key"] return?
Want more? Practise all ASP.NET MVC MCQs · ASP.NET MVC interview questions
My notes#
Saved in this browser.