简体   繁体   中英

Strongly typed calls into web.config without duplicating the property names?

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?

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 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_", "")];

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!)

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 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!

使用Configuration Section Designer构建您自己的ConfigurationSection ,这样您就不必使用AppSettings了......但是您将拥有自己的设置集合,甚至在web.config文件中都有Intellisense。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM