Question

I searched here for the answer. I'm sorry if this has been asked before (as I suspect it has).

Summary: How can I have strongly typed calls into my web.config without duplicating the property names?


Details: In my code, I try to minimize string usage, and I don't like defining something twice.

Complementing both of these wonts is my restriction of AppSettings usage (and its strings) to one class, which I reference throughout the project. The AppSettings class exposes public properties:

    12   public static string DateFormatString {
    13       get {
    14           return ConfigurationManager.AppSettings["DateFormatString"];
    15       }
    16   }

How can I keep this class and prevent the duplication (lines 12 & 14) of the property name?

Alternatively, what other solution might you recommend?

Was it helpful?

OTHER TIPS

There's no duplication in your example: One DateFormatString is a property name and the other is a string. You're just following a convention which names the property identically to the lookup key for the value.

I do see one possible improvement. You should read the config file once in a static constructor and store the values instead of reading them from AppSettings every time a property is accessed.

I'd probably recommend deserializing the web.config into an object. You can then access all configuration entries as if they were properties (can't get much more strongly typed than that!)

I create a wrapper for everything that doesn't belong to me directly. This includes cache, session, configuration, external web services, etc. This allows me to encapsulate the dirty details of using that widget. In the case of configuration I have a bare bones configuration class that exposes the various properties that I have housed my app.config or web.config. This might look something like this:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using RanchBuddy.Core.Services.Impl;
using StructureMap;

namespace RanchBuddy.Core.Services.Impl
{
    [Pluggable("Default")]
    public class ConfigurationService : IConfigurationService
    {
        internal static int GetDefaultCacheDuration_Days()
        {
            return Convert.ToInt32(ConfigurationManager.AppSettings["DefaultCacheDuration_Days"]);
        }

        ...

        internal static LoggingType GetLoggingType()
        {
            string loggingType = ConfigurationManager.AppSettings["LoggingType"].ToString();
            if(loggingType.ToLower() == "verbose")
            {
                return LoggingType.Verbose;
            }
            else if (loggingType.ToLower() == "error")
            {
                return LoggingType.Error;
            }
            return LoggingType.Error;
        }

        ...

        public static string GetRoot()
        {
            string result = "";
            if(ConfigurationManager.AppSettings["Root"] != null)
            {
                result = ConfigurationManager.AppSettings["Root"].ToString();
            }
            return result;
        }
    }
}

Inside here you can do more than simply get values from the config file. You can convert a string to the type that it needs to be. You can use the string to determine an enum value to be returned. Etc. But the key is that any changes that ever need to be made regarding configuration can be made here. To include if you want to swap out the mechanism for the configuration store!

Build your own ConfigurationSection with the Configuration Section Designer, this way you don't have to use AppSettings at all... but you'll have your own collection of settings that will even have Intellisense in the web.config file.

One solution could be,

public enum Settings
{
    None,
    DateFormatString,
    DefeaultUserPrefix,
    SomeOtherValue
}

and then have a helper class like,

public static class ConfigurationHelper
{
     public static Get<T>(Settings setting)
     {
         string output = ConfigurationManager.AppSettings[setting.ToString()];
         if(string.isNullOrEmpty(output))
               throw new ConfigurationErrorsException("Setting " + setting + " is not defined in Configuration file.");
         return (T)output; //You can probably use Convert.* functions. 
     }
}

Your calling code will look like,

ConfigurationHelper.Get<string>(Settings.DateFormatString);

The above approach provides some level of strong typing but you still have to make sure that the settings name in config file matches with the name of the enum.

The best choice would be to auto-generate class based on the configuration file.


If you wanted strongly typed properties, you can write

public static string DateFormatString
{
    get { return ConfigurationHelper.Get<string>(Settings.DateFormatString); }
}

Also, I would advice against reading the config file in constructor (premature optimization?). If you read the config file in constructor, it means that you can not change config file while application is running.

I have written a nuget package that does this (among other things). The accompanying blog post goes in to the details, but this simplified snippet shows the gist of it as related to your question.

public string DateFormatString =>
    ConfigurationManager.AppSettings[MethodBase.GetCurrentMethod().Name.Replace("get_", "")];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top