Question
How to Read app.config and web.config Settings in .NET Class Libraries
Question
I'm working on a C# class library that needs to read settings from either web.config or app.config, depending on whether the DLL is used by an ASP.NET web application or a Windows Forms application.
I found that this works:
ConfigurationSettings.AppSettings.Get("MySetting");
However, Microsoft has marked that API as deprecated.
I also read that I should use this instead:
ConfigurationManager.AppSettings["MySetting"];
But System.Configuration.ConfigurationManager does not seem to be available in my C# class library project.
What is the best way to read configuration values in this situation?
Short Answer
By the end of this page, you will understand how configuration works for .NET class libraries, why ConfigurationSettings is deprecated, how to use ConfigurationManager.AppSettings, and why class libraries usually read configuration from the host application's config file rather than their own separate config file.
Concept
In .NET, a class library does not usually own the application configuration file. The configuration belongs to the host application that loads the library.
That means:
- A Windows Forms app typically uses
app.config - An ASP.NET app typically uses
web.config - Your DLL reads from whichever configuration file belongs to the running application
The important idea is that your library usually does not need to know whether the host is web or desktop. It simply reads configuration through the .NET configuration API, and the runtime resolves the correct host config source.
Older code often uses:
ConfigurationSettings.AppSettings.Get("MySetting")
This API is deprecated. The recommended API in classic .NET is:
ConfigurationManager.AppSettings["MySetting"]
If ConfigurationManager is not available, the usual reason is that your project is missing a reference to the configuration assembly/package.
In classic .NET Framework projects, you typically add a reference to:
System.Configuration
Then import the namespace:
using System.Configuration;
After that, your class library can read values from the host application's configuration.
A common AppSettings entry looks like this:
<appSettings>
<add key="MySetting" value="Hello" />
</appSettings>
And you read it like this:
string value = ConfigurationManager.AppSettings["MySetting"];
This matters because configuration is one of the main ways applications provide environment-specific values such as:
- connection strings
- API endpoints
- feature flags
- file paths
- timeout values
A well-designed library can read config values, but in many real projects it is even better to let the application pass settings into the library explicitly. That makes the library easier to test and reuse.
Mental Model
Think of a class library as a tool used inside a larger machine.
- The application is the machine
- The config file is the machine's settings panel
- The class library is one tool inside the machine
The tool does not carry its own main settings panel. Instead, it reads the settings of the machine that is currently using it.
So if your DLL is loaded by:
- a web app, it reads the web app's configuration
- a desktop app, it reads the desktop app's configuration
Your library asks the runtime, "What are the current application settings?" It does not normally ask, "Am I in a web app or a Windows app?"
Syntax and Examples
The usual approach in a .NET Framework class library is:
using System.Configuration;
public class SettingsReader
{
public string GetMySetting()
{
return ConfigurationManager.AppSettings["MySetting"];
}
}
Required configuration entry
For a desktop app (app.config) or web app (web.config):
<configuration>
<appSettings>
<add key="MySetting" value="Hello from config" />
</appSettings>
</configuration>
Example with a null check
using System;
using System.Configuration;
public class SettingsReader
{
public string GetRequiredSetting(string key)
{
string value = ConfigurationManager.AppSettings[key];
if (string.IsNullOrEmpty(value))
{
throw new InvalidOperationException($"Missing app setting: {key}");
}
return value;
}
}
This example is safer because missing settings are common in real projects.
If ConfigurationManager is missing
In classic .NET Framework:
- add a reference to
System.Configuration - add
using System.Configuration;
In newer SDK-style projects, you may need the NuGet package:
System.Configuration.ConfigurationManager
Then this code becomes available:
string value = ConfigurationManager.AppSettings["MySetting"];
Step by Step Execution
Consider this code:
using System;
using System.Configuration;
public class SettingsReader
{
public void PrintSetting()
{
string value = ConfigurationManager.AppSettings["MySetting"];
if (value == null)
{
Console.WriteLine("Setting not found.");
return;
}
Console.WriteLine(value);
}
}
And this config:
<appSettings>
<add key="MySetting" value="Blue" />
</appSettings>
Step by step:
- The application starts.
- The .NET runtime loads the host application's configuration file.
- Your class library method
PrintSetting()runs. ConfigurationManager.AppSettings["MySetting"]looks in the host config's<appSettings>section.- If the key exists, it returns the value as a string.
- If the key does not exist, it returns
null. - The code checks for
null. - If found, it prints
Blue; otherwise it printsSetting not found.
This is why the library works in both web and desktop apps without separate code paths.
Real World Use Cases
Configuration settings are used everywhere in real applications.
API base URLs
<appSettings>
<add key="ApiBaseUrl" value="https://api.example.com" />
</appSettings>
A library that calls external services can read this value.
Feature flags
<appSettings>
<add key="EnableCaching" value="true" />
</appSettings>
A library can enable or disable behavior based on a setting.
File paths
<appSettings>
<add key="LogFolder" value="C:\Logs" />
</appSettings>
Useful for export tools, logging helpers, or report generators.
Timeouts and limits
<appSettings>
<add key="RetryCount" value="3" />
</appSettings>
Libraries often need configurable retry counts, batch sizes, or timeout values.
Multi-environment deployment
Different apps can use the same DLL but provide different config values for:
- development
- test
- staging
- production
That makes the library reusable without code changes.
Real Codebase Usage
In real projects, developers often go beyond directly reading AppSettings everywhere.
Common pattern: wrap configuration access
Instead of scattering calls to ConfigurationManager.AppSettings throughout the codebase, developers often centralize it:
using System;
using System.Configuration;
public static class AppConfig
{
public static string GetRequired(string key)
{
string value = ConfigurationManager.AppSettings[key];
if (string.IsNullOrWhiteSpace(value))
{
throw new InvalidOperationException($"Missing configuration value: {key}");
}
return value;
}
}
This improves:
- validation
- consistency
- testability
- error messages
Guard clauses
A common practice is to fail early if config is missing:
string apiUrl = AppConfig.GetRequired("ApiBaseUrl");
This avoids mysterious bugs later.
Parse typed values carefully
AppSettings stores strings, so real codebases often convert them:
int retryCount = int.Parse(ConfigurationManager.AppSettings["RetryCount"]);
A safer version is:
if (!int.TryParse(ConfigurationManager.AppSettings["RetryCount"], out int retryCount))
{
retryCount = 3;
}
Better design: pass settings into the library
Although a library can read config directly, many teams prefer dependency injection or constructor parameters:
public class EmailService
{
private readonly string _smtpServer;
public EmailService(string smtpServer)
{
_smtpServer = smtpServer;
}
}
Then the application reads config and passes it in. This makes the library:
- easier to test
- less tightly coupled to configuration APIs
- easier to reuse in different hosts
Legacy and modern projects
In older .NET Framework codebases, ConfigurationManager is common.
In modern .NET applications, configuration is often handled through IConfiguration and JSON files such as appsettings.json.
But for app.config and web.config, ConfigurationManager remains the main classic solution.
Common Mistakes
1. Forgetting to add the assembly/package reference
If this fails to compile:
ConfigurationManager.AppSettings["MySetting"];
you may be missing:
- the
System.Configurationreference in .NET Framework - or the
System.Configuration.ConfigurationManagerpackage in newer projects
2. Forgetting the namespace
Broken code:
public class Test
{
public string Read()
{
return ConfigurationManager.AppSettings["MySetting"];
}
}
Fix:
using System.Configuration;
3. Assuming the library has its own active config file
Beginners sometimes expect the DLL to automatically use a separate config file. Usually it does not. It reads from the host application's config.
4. Not handling missing keys
Broken code:
string name = ConfigurationManager.AppSettings["UserName"];
Console.WriteLine(name.Length);
If the key is missing, name is null, and this throws an exception.
Safer code:
string name = ConfigurationManager.AppSettings["UserName"];
if (string.IsNullOrEmpty(name))
{
Console.WriteLine("UserName is missing.");
}
else
{
Console.WriteLine(name.Length);
}
5. Forgetting that all values are strings
Broken code:
int retryCount = ConfigurationManager.AppSettings["RetryCount"];
Fix:
int retryCount = int.Parse(ConfigurationManager.AppSettings["RetryCount"]);
Safer fix:
int.TryParse(ConfigurationManager.AppSettings["RetryCount"], out int retryCount);
6. Using deprecated ConfigurationSettings
Older code:
ConfigurationSettings.AppSettings.Get("MySetting");
Preferred code:
ConfigurationManager.AppSettings["MySetting"];
7. Hard-coding defaults without documenting them
If a config value is optional, make the fallback clear in code:
string mode = ConfigurationManager.AppSettings["Mode"] ?? "Standard";
Comparisons
| Approach | Typical use | Pros | Cons |
|---|---|---|---|
ConfigurationSettings.AppSettings.Get() | Older .NET code | Works in legacy code | Deprecated |
ConfigurationManager.AppSettings[] | Classic .NET config access | Standard, simple, widely used | Returns only strings |
| Pass settings into the library | Reusable library design | Easier to test and decouple | Requires setup in the host app |
IConfiguration | Modern .NET apps | Flexible, strongly integrated with DI | Not the classic app.config/web.config approach |
ConfigurationSettings vs ConfigurationManager
- Use
ConfigurationManagerfor classic .NET configuration access. - Avoid
ConfigurationSettingsin new or updated code.
Direct config access vs injected settings
| Style | Good when | Trade-off |
|---|---|---|
| Library reads config directly | Small legacy apps, quick integration | Tighter coupling to config system |
| Application passes settings to library | Clean architecture, testing, reuse | Slightly more setup |
If you are maintaining an older .NET Framework project, direct use of ConfigurationManager is normal. If you are designing a reusable library, injected settings are often better.
Cheat Sheet
using System.Configuration;
string value = ConfigurationManager.AppSettings["MySetting"];
Config entry
<configuration>
<appSettings>
<add key="MySetting" value="Hello" />
</appSettings>
</configuration>
Key points
ConfigurationSettingsis deprecated- Use
ConfigurationManager.AppSettings[key] - Add reference to
System.Configurationin .NET Framework - In newer projects, you may need the
System.Configuration.ConfigurationManagerpackage - A class library usually reads from the host application's config file
AppSettingsvalues are always strings- Missing keys return
null
Safe read pattern
string value = ConfigurationManager.AppSettings["MySetting"];
if (string.IsNullOrWhiteSpace(value))
{
throw new InvalidOperationException("Missing setting: MySetting");
}
Parse numbers safely
int.TryParse(ConfigurationManager.AppSettings["RetryCount"], out int retryCount);
Best practice
- For simple legacy apps: read via
ConfigurationManager - For reusable libraries: prefer passing settings into the library when possible
FAQ
How does a class library know whether to use app.config or web.config?
It usually does not need to know. The .NET runtime uses the configuration file of the host application that loads the library.
Why is ConfigurationManager missing in my class library?
Your project is likely missing the required reference or package. In .NET Framework, add System.Configuration. In newer projects, install System.Configuration.ConfigurationManager.
Is ConfigurationSettings.AppSettings.Get() still usable?
It may still work in older projects, but it is deprecated. Prefer ConfigurationManager.AppSettings[...].
Can a DLL have its own separate config file?
Not in the usual automatic way people expect. Typically, the active configuration comes from the host application, not the DLL itself.
What happens if a setting key does not exist?
ConfigurationManager.AppSettings[key] returns null, so your code should handle that safely.
Are app settings strongly typed?
No. Values from AppSettings are strings. You must parse them into int, bool, or other types yourself.
What is the best design for reusable libraries?
Often the best design is for the application to read configuration and pass values into the library, rather than the library reading config directly.
Should I use ConfigurationManager in modern .NET applications?
For classic app.config and web.config, yes. For modern .NET apps, IConfiguration with appsettings.json is more common.
Mini Project
Description
Build a small configuration reader class for a reusable .NET library. The project demonstrates how a class library reads values from the host application's configuration file and how to validate required settings safely.
Goal
Create a class that reads required and optional application settings using ConfigurationManager and handles missing values cleanly.
Requirements
- Create a class library class named
AppSettingsReader - Read one required setting and one optional setting from configuration
- Throw a clear exception when the required setting is missing
- Return a default value when the optional setting is missing
- Show an example
app.configorweb.configentry
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Access Modifiers and static: public, private, protected, and Defaults
Learn how C# public, private, protected, and default access control visibility, and how static differs from instance members.