1

I want to use a string array stored in the web.config to easily change its values, this is in the format: full_w=670|small_w=100,q=low|tiny_h=30,c=true. Each template is split by the | (pipe) and then each of those sets comprises of a name (left of _) and its corresponding values (right of _), the values can be several and each separated by the , (comma). I think this possibly qualifies for a 3D array, I just can't seem to get an easy way to read this in a sensible manner. Any ideas or solutions as to the best way to read/manage the data from this string?

Basically, in the end I want to be able to call the template small and read its values which in this case are width=100 and quality=low.

Nelson Pires
  • 321
  • 4
  • 12
  • To make it easy you can save it into a Dictionary (Key, Value) pair. Key being full, small, tiny and the values being (full: w670), (small: w100, qlow). Just know that when you treat your value the first letter will be the identifier – FirebladeDan Jul 28 '15 at 18:04

2 Answers2

2

Here's the function I wrote to parse one of these settings strings:

public static Dictionary<string, Dictionary<string, string>> getSettings(string settingsStr)
{
    return settingsStr.Split('|').ToDictionary(
        template => template.Split('_')[0],
        template => template.Split('_')[1].Split(',').ToDictionary(
            setting => setting.Split('=')[0],
            setting => setting.Split('=')[1]));
}

It just uses a lot of string .Splitting and .ToDictionarying.

Here's the test, showing that it works:

var result = getSettings("full_w=670|small_w=100,q=low|tiny_h=30,c=true");
/*
result = {
    [ "full" => [ "w" => "670" ] ]
    [ "small" => [ "w" => "100", "q" => "low" ] ]
    [ "tiny" => [ "h" => "30", "c" => "true" ] ]
}
*/

To read the values w and q from template small, you can do this:

int width = int.Parse(result["small"]["w"]);
string quality = result["small"]["q"];

Edit: As an added bonus, if you want to convert the Dictionary<string, Dictionary<string, string>> back into a single settings sting, you can use this method:

public static string getSettingsStr(Dictionary<string, Dictionary<string, string>> settings)
{
    return string.Join("|",
        settings.Select(kvp =>
            kvp.Key + "_" + string.Join(",",
                kvp.Value.Select(setting =>
                    setting.Key + "=" + setting.Value))));
}

Use:

string settingsStr = getSettingsStr(result);
// settingsStr = "full_w=670|small_w=100,q=low|tiny_h=30,c=true"

If you want to check that a specific template or setting exists, then use the .ContainsKey() method:

// If I have "Dictionary<string, Dictionary<string, string>> settings;"
int width = -1;
string quality = null;
if (settings.ContainsKey("small"))
{
    if (settings["small"].ContainsKey("w"))
        width = int.Parse(settings["small"]["w"]);
    if (settings["small"].ContainsKey("q"))
        quality = settings["small"]["q"];
}
Jashaszun
  • 9,207
  • 3
  • 29
  • 57
  • I like it, really like it. Its a dictionary of dictionaries and woks well for my needs, this is the accepted answer. One more thing; how to return null or empty if a key is not present in the dictionary, like; `result["small"]["a"];`? Thanks. – Nelson Pires Jul 28 '15 at 22:02
  • @NelsonPires With this solution, it is much better to simply check whether the template/setting exists (with the `.ContainsKey(key)` method). Also, if this is the answer, then consider marking it as such, so that future visitors can easily tell. – Jashaszun Jul 28 '15 at 22:04
  • Can't find the `.ContainsKey(key)`, can you provide an example? Marked as accepted, thanks. – Nelson Pires Jul 28 '15 at 22:08
  • Great, works perfectly. I wonder that since I am reading the web.config and this is going to be used in an image handler, for the cases of a large gallery, will the web.config be hit/read per image of the .net framework caches the web.config values and uses that until the file is modified? – Nelson Pires Jul 29 '15 at 11:10
  • Just found out the answer to my last question and for posterity in case anyone also needs to know, the web.config is not hit every time a value from it is read, the framework keeps it in memory until the application is restarted or the file is modified which also restarts the application. – Nelson Pires Jul 29 '15 at 18:49
0

Have you considered using plain old XML Serialization with your own plain old C# objects. Here is an example:

public class Program
{
    static void Main(string[] args)
    {
        var data = new MyConfig[2];

        for (int i = 0; i < 2; i++)
        {
            data[i] = new MyConfig { Name = "Name" + i };

            data[i].Properties = new MyConfigAttribute[]
            {
                new MyConfigAttribute { Name = "Property Name " + i, Value = "Property Value " + i },
                new MyConfigAttribute { Name = "2nd Property Name " + i, Value = "2nd Property Value " + i },
            };
        }

        var serializer = new XmlSerializer(typeof(MyConfig[]));
        using (StreamWriter tw = File.CreateText(@"c:\temp\myconfig.xml"))
        {
            serializer.Serialize(tw, data);
        }

        using (StreamReader tw = File.OpenText(@"c:\temp\myconfig.xml"))
        {
            var readBack = serializer.Deserialize(tw);
        }


        Console.ReadLine();
    }

    [XmlRoot("MY_CONFIG")]
    public class MyConfig
    {
        [XmlElement("NAME")]
        public string Name { get; set; }

        [XmlArray]
        [XmlArrayItem(typeof(MyConfigAttribute))]
        public MyConfigAttribute[] Properties { get; set; }
    }

    [XmlRoot("MY_CONFIG_ATTRIBUTE")]
    public class MyConfigAttribute
    {
        [XmlElement("ATTRIBUTE_NAME")]
        public string Name { get; set; }

        [XmlElement("ATTRIBUTE_VALUE")]
        public string Value { get; set; }
    }
}

Basically, you create a class to store your individual attributes (MyConfigAttribute in this case), wrap it in another class to provide your name for a group of related attributes (MyConfig in this case), then use normal XML Serialization to write the settings out to an individual XML file, like this section of the code

        var serializer = new XmlSerializer(typeof(MyConfig[]));
        using (StreamWriter tw = File.CreateText(@"c:\temp\myconfig.xml"))
        {
            serializer.Serialize(tw, data);
        }

You can read it back to objects again using this section of the code:

        using (StreamReader tw = File.OpenText(@"c:\temp\myconfig.xml"))
        {
            var readBack = serializer.Deserialize(tw);
        }

The advantage of this is:

  • It is simple to understand and use
  • You can add features to your custom class, e.g. to add values to the array of properties, thereby lending itself to wrapping a custom screen around it.

Look up C# XML Serialization on Google!

  • Thanks Richard but I'm reading from web.config and as such don't need to use another xml file, but your answer might come in handy for other things. Thanks once again. – Nelson Pires Jul 28 '15 at 22:10
  • Nelson, if you really need to use the web config file then you should explore writing custom sections [link](http://stackoverflow.com/questions/5027284/nested-configuration-section-app-config) – Richard Leeman Jul 28 '15 at 22:45
  • `` is fine for my needs and it can read/write easily, but thanks for the advice. – Nelson Pires Jul 29 '15 at 18:51