1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections.Specialized;
6 using System.Globalization;
7 
8 namespace System.Configuration
9 {
10     /// <summary>
11     ///     The AppSettingsReader class provides a wrapper for System.Configuration.ConfigurationManager.AppSettings
12     ///     which provides a single method for reading values from the config file of a particular type.
13     /// </summary>
14     public class AppSettingsReader
15     {
16         private NameValueCollection _map;
17         private static Type s_stringType = typeof(string);
18         private static Type[] _paramsArray = new Type[] { s_stringType };
19         private static string NullString = "None";
20 
AppSettingsReader()21         public AppSettingsReader()
22         {
23             _map = System.Configuration.ConfigurationManager.AppSettings;
24         }
25 
26         /// <summary>
27         /// Gets the value for specified key from ConfigurationManager.AppSettings, and returns
28         /// an object of the specified type containing the value from the config file.  If the key
29         /// isn't in the config file, or if it is not a valid value for the given type, it will
30         /// throw an exception with a descriptive message so the user can make the appropriate
31         /// change
32         /// </summary>
GetValue(string key, Type type)33         public object GetValue(string key, Type type)
34         {
35             if (key == null) throw new ArgumentNullException(nameof(key));
36             if (type == null) throw new ArgumentNullException(nameof(type));
37 
38             string val = _map[key];
39 
40             if (val == null) throw new InvalidOperationException(string.Format(SR.AppSettingsReaderNoKey, key));
41 
42             if (type == s_stringType)
43             {
44                 // It's a string, so we can ALMOST just return the value.  The only
45                 // tricky point is that if it's the string "(None)", then we want to
46                 // return null.  And of course we need a way to represent the string
47                 // (None), so we use ((None)), and so on... so it's a little complicated.
48                 int NoneNesting = GetNoneNesting(val);
49                 if (NoneNesting == 0)
50                 {
51                     // val is not of the form ((..((None))..))
52                     return val;
53                 }
54                 else if (NoneNesting == 1)
55                 {
56                     // val is (None)
57                     return null;
58                 }
59                 else
60                 {
61                     // val is of the form ((..((None))..))
62                     return val.Substring(1, val.Length - 2);
63                 }
64             }
65             else
66             {
67                 try
68                 {
69                     return Convert.ChangeType(val, type, CultureInfo.InvariantCulture);
70                 }
71                 catch (Exception)
72                 {
73                     string displayString = (val.Length == 0) ? SR.AppSettingsReaderEmptyString : val;
74                     throw new InvalidOperationException(string.Format(SR.AppSettingsReaderCantParse, displayString, key, type.ToString()));
75                 }
76             }
77         }
78 
GetNoneNesting(string val)79         private int GetNoneNesting(string val)
80         {
81             int count = 0;
82             int len = val.Length;
83             if (len > 1)
84             {
85                 while (val[count] == '(' && val[len - count - 1] == ')')
86                 {
87                     count++;
88                 }
89                 if (count > 0 && string.Compare(NullString, 0, val, count, len - 2 * count, StringComparison.Ordinal) != 0)
90                 {
91                     // the stuff between the parens is not "None"
92                     count = 0;
93                 }
94             }
95             return count;
96         }
97     }
98 }
99