How to easily access a web.config AppSettings value with a Type and a default value?
Update: This is now in my Rhyous.Collections NuGet package and you can see the source on GitHub: NameValueCollectionExtensions.cs
I wanted to make it easier to get a value from AppSettings in the web.config (or the app.config if you aren’t doing web) while converting to the proper type and having a default value.
Here is the syntax I started with that I didn’t like at all.
public static int MaxRetryAttempts = (string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["SmptRetries"]))
? int.Parse(ConfigurationManager.AppSettings["SmptRetries"])
: 3;
I decided I wanted to have the following syntax:
ConfigurationManager.AppSettings.Get<T>(string key, T defaultValue)
I found a blog post that got me started. His syntax was very close to what I wanted already. He didn’t have the default value and he wasn’t an extension method, but wow, was this a real help. I was unaware of TypeDescriptor.GetConverter and was going to basically roll my own with an massively ugly case statement. So I am very happy I found his post.
I created the following NameValueCollectionExtensions.cs file.
using System.Collections.Specialized;
using System.ComponentModel;
namespace Rhyous.Extensions
{
public static class NameValueCollectionExtensions
{
public static T Get<T>(this NameValueCollection collection, string key, T defaultValue)
{
var value = collection[key];
var converter = TypeDescriptor.GetConverter(typeof(T));
if (string.IsNullOrWhiteSpace(value) || !converter.IsValid(value))
{
return defaultValue;
}
return (T)(converter.ConvertFromInvariantString(value));
}
}
}
Details
- ConfigurationManager.AppSettings is of Type System.Collections.Specialized.NameValueCollection. So my extension method must be for that type.
- I changed the author’s method to be an extension method using the “this” keyword.
- I changed from using ConfirationManager.AppSettings to use the first parameter, collection, defined by the “this” keyword.
- I added a parameter for a default value.
- I changed the method code to return the default value, instead of throwing an exception, if the setting in the web.config is missing or empty.
Usage
I have to retry sending emails. I want the SmtpRetries to be an int obtained from the web.config’s AppSettings and have a default value of 3.
public static int MaxRetryAttempts = ConfigurationManager.AppSettings.Get("SmptRetries", 3);
Unit Tests
I really only wrote unit tests for int conversion. I expect that is sufficient. But if you want to write tests for a double or a other type feel free.
using System;
using System.Collections.Specialized;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Rhyous.Extensions.Tests
{
[TestClass]
public class NameValueCollectionExtensionsTests
{
private const string Name = "Retries";
[TestMethod]
public void IntValueExistsTest()
{
// Arrange
const int defaultMaxRetries = 2;
const int value = 3;
var collection = new NameValueCollection { { Name, value.ToString() } };
// Act
var actual = collection.Get(Name, defaultMaxRetries);
// Assert
Assert.AreEqual(value, actual, "Valid value should return the valid value.");
}
[TestMethod]
public void IntValueDoesNotExistTest()
{
// Arrange
const int defaultMaxRetries = 2;
var collection = new NameValueCollection();
// Act
var actual = collection.Get(Name, defaultMaxRetries);
// Assert
Assert.AreEqual(defaultMaxRetries, actual, "Missing value returns default.");
}
[TestMethod]
public void IntValueIsEmptyStringTest()
{
// Arrange
const int defaultMaxRetries = 2;
var collection = new NameValueCollection { { Name, string.Empty } };
// Act
var actual = collection.Get(Name, defaultMaxRetries);
// Assert
Assert.AreEqual(defaultMaxRetries, actual, "Empty string returns default.");
}
[TestMethod]
public void IntValueIsWhiteSpaceStringTest()
{
// Arrange
const int defaultMaxRetries = 2;
var collection = new NameValueCollection { { Name, " " } };
// Act
var actual = collection.Get(Name, defaultMaxRetries);
// Assert
Assert.AreEqual(defaultMaxRetries, actual, "Whitespace string returns default.");
}
[TestMethod]
public void IntValueIsDoubleTest()
{
// Arrange
const int defaultMaxRetries = 2;
const double value = 3.5;
var collection = new NameValueCollection { { Name, value.ToString() } };
// Act
var actual = collection.Get(Name, defaultMaxRetries);
// Assert
Assert.AreEqual(defaultMaxRetries, actual, "Invalid value returns default.");
}
[TestMethod]
public void IntValueIsCharsTest()
{
// Arrange
const int defaultMaxRetries = 2;
const string value = "abc";
var collection = new NameValueCollection { { Name, value } };
// Act
var actual = collection.Get(Name, defaultMaxRetries);
// Assert
Assert.AreEqual(defaultMaxRetries, actual, "Invalid value returns default.");
}
}
}


Thanks for creating NameValueCollectionExtensions. I found your link on StackOverflow but having only just joined SO I don't have sufficient "reputation" to UpVote it. However your code works a treat!
Ahh - so site is stripping out the < T > symbols
That is weird. I have a plugin that is supposed to prevent exactly that from happening. I wonder why it failed this time. Anyway, I fixed it.
Thanks!
Nice! - small typo in the code for the extension however:
should be:
Jim
Thanks. Fixed!
FYI, I have a link just below the comment box that says: How to post code in comments?