views:

283

answers:

3

Currently in my ASP.Net applications web.config I have an application setting that stores a comma delimited list of mapping values, like the one below. In the code behind I need to perform a lookup on this data based on input values 1, 2, 3 etc. I can either string split it and loop until I find a match, or use Regex to pull the value from the config string.

Currently i'm using Regex to get the mapping value. I'm not opposed to changing how the data is stored in the web.config. Is there a more simple and elegant way of handling this?

<add key="Mappings" value="1|APP,2|TRG,3|KPK,4|KWT,5|CUT" />
A: 

Split the string on commas, then each substring on |, store these in a Dictionary and find it by key.

That's just as an alternative to Regex. You know what they say about Regex.

Moose
No, actually I don't know what they say about Regex. Is it not a good idea to use it for this? I would think Regex would be the best performing solution since no arrays need to be initialized.
James
It was kind of a joke. the quote I've seen thrown around here is "When you solve a problem using Regex, now you have two problems." The Regex Version is probably a more elegant solution, but if speed is an issue, you can cache the web.config string as well as the Dictionary.
Moose
Then, when you have another request for a lookup, compare the cached string with the web.config string, if it's different, rebuild the dictionary. Unless you have a *huge* set, I don't think performance is really going to be an issue either way.
Moose
+1  A: 

Just curious :) What about LINQ

string inputValue = "2";
string fromConfig = "1|APP,2|TRG,3|KPK,4|KWT,5|CUT";      
string result = fromConfig
    .Split(',')
    .Where(s => s.StartsWith(inputValue))
    .Select(s => s.Split('|')[1])
    .FirstOrDefault();

Or

Regex parseRegex = new Regex(@"((?<Key>\d)\|(?<Value>\S{3}),?)");
parseRegex.Matches(fromConfig)
    .Cast<Match>()
    .Where(m => m.Groups["Key"].Value == inputValue)
    .Select(m => m.Groups["Value"].Value)
    .FirstOrDefault();
Mike Chaliy
+1  A: 

If you need to use this lookup frequently and the string in web.config doesn't change very often, then it makes sense to parse the string once into a Dictionary object and store that in the Application or Cache.

Lookups from the Dictionary will be lightning fast, especially compared to parsing the string each time.

private static readonly object _MappingsLock = new object();

public static string GetMapping(int id)
{
    // lock to avoid race conditions
    lock (_MappingsLock)
    {
        // try to get the dictionary from the application object
        Dictionary<int, string> mappingsDictionary =
            (Dictionary<int, string>)Application["MappingsDictionary"];

        if (mappingsDictionary == null)
        {
            // the dictionary wasn't found in the application object
            // so we'll create it from the string in web.config
            mappingsDictionary = new Dictionary<int, string>();

            foreach (string s in mappingsStringFromWebConfig.Split(','))
            {
                string[] a = s.Split('|');
                mappingsDictionary.Add(int.Parse(a[0]), a[1]);
            }

            // store the dictionary in the application object
            // next time around we won't need to recreate it
            Application["MappingsDictionary"] = mappingsDictionary;
        }

        // now do the lookup in the dictionary
        return mappingsDictionary[id];
    }
}

// eg, get the mapping for id 4
string mapping = GetMapping(4);  // returns "KWT"
LukeH
Yeah, I know there's a potential race condition in there, and no exception handling, but this is just proof-of-concept code ;)
LukeH
So to handle the race condition would you throw a lock statement around the part that adds to the cache?
James
@James, That's exactly what I'd do. I'll update the example code.
LukeH