2 // System.Configuration.ConfigurationSettings.cs
5 // Christopher Podurgiel (cpodurgiel@msn.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // C) Christopher Podurgiel
9 // (c) 2002 Ximian, Inc. (http://www.ximian.com)
13 using System.Collections;
14 using System.Collections.Specialized;
16 using System.Runtime.CompilerServices;
18 using System.Xml.XPath;
20 namespace System.Configuration
22 public sealed class ConfigurationSettings
24 static IConfigurationSystem config;
26 private ConfigurationSettings ()
30 public static object GetConfig (string sectionName)
33 config = DefaultConfig.GetInstance ();
35 return config.GetConfig (sectionName);
38 public static NameValueCollection AppSettings
41 object appSettings = GetConfig ("appSettings");
42 if (appSettings == null)
43 appSettings = new NameValueCollection ();
45 return (NameValueCollection) appSettings;
52 // class DefaultConfig: read configuration from machine.config file and application
53 // config file if available.
55 class DefaultConfig : IConfigurationSystem
57 static string creatingInstance = "137213797382-asad";
58 static string buildingData = "1797382-ladgasjkdg";
59 static DefaultConfig instance;
60 ConfigurationData config;
62 private DefaultConfig ()
66 public static DefaultConfig GetInstance ()
68 if (instance == null) {
69 lock (creatingInstance) {
70 if (instance == null) {
71 instance = new DefaultConfig ();
81 public object GetConfig (string sectionName)
86 return config.GetConfig (sectionName);
96 ConfigurationData data = new ConfigurationData ();
97 if (data.Load (GetMachineConfigPath ())) {
98 ConfigurationData appData = new ConfigurationData (data);
99 appData.Load (GetAppConfigPath ());
102 Console.WriteLine ("** Warning **: cannot find " + GetMachineConfigPath ());
103 Console.WriteLine ("Trying to load app config file...");
104 data.Load (GetAppConfigPath ());
111 [MethodImplAttribute(MethodImplOptions.InternalCall)]
112 extern private static string get_machine_config_path ();
114 private static string GetMachineConfigPath ()
116 return get_machine_config_path ();
119 private static string GetAppConfigPath ()
121 AppDomainSetup currentInfo = AppDomain.CurrentDomain.SetupInformation;
123 string configFile = currentInfo.ConfigurationFile;
124 if (configFile == null || configFile.Length == 0)
132 class ConfigurationData
134 ConfigurationData parent;
137 object removedMark = new object ();
138 object groupMark = new object ();
140 public ConfigurationData () : this (null)
144 public ConfigurationData (ConfigurationData parent)
146 this.parent = (parent == this) ? null : parent;
147 factories = new Hashtable ();
150 public bool Load (string fileName)
152 if (fileName == null)
155 this.fileName = fileName;
156 XmlTextReader reader = null;
160 reader = new XmlTextReader (fileName);
166 ReadConfigFile (reader);
175 object GetHandler (string sectionName)
177 object o = factories [sectionName];
178 if (o == null || o == removedMark) {
180 return parent.GetHandler (sectionName);
185 if (o is IConfigurationSectionHandler)
186 return (IConfigurationSectionHandler) o;
188 Type t = Type.GetType ((string) o);
190 throw new ConfigurationException ("Cannot get Type for " + o);
192 Type iconfig = typeof (IConfigurationSectionHandler);
193 if (!iconfig.IsAssignableFrom (t))
194 throw new ConfigurationException (sectionName + " does not implement " + iconfig);
196 o = Activator.CreateInstance (t, true);
198 throw new ConfigurationException ("Cannot get instance for " + t);
200 factories [sectionName] = o;
205 //TODO: Should use XPath when it works properly for this.
206 XmlDocument GetDocumentForSection (string sectionName)
208 ConfigXmlDocument doc = new ConfigXmlDocument ();
209 XmlTextReader reader = null;
211 reader = new XmlTextReader (fileName);
217 string [] sectionPath = sectionName.Split ('/');
220 if (reader.Name == "configSections")
222 while (!reader.EOF) {
223 if (reader.NodeType == XmlNodeType.Element &&
224 reader.Name == sectionPath [i]) {
225 if (++i == sectionPath.Length) {
226 doc.LoadSingleElement (fileName, reader);
229 MoveToNextElement (reader);
233 if (reader.NodeType != XmlNodeType.Element)
234 MoveToNextElement (reader);
242 public object GetConfig (string sectionName)
244 object handler = GetHandler (sectionName);
248 if (!(handler is IConfigurationSectionHandler))
251 object parentConfig = null;
253 parentConfig = parent.GetConfig (sectionName);
255 XmlDocument doc = GetDocumentForSection (sectionName);
257 if (parentConfig == null)
263 return ((IConfigurationSectionHandler) handler).Create (parentConfig, null, doc);
266 private object LookForFactory (string key)
268 object o = factories [key];
273 return parent.LookForFactory (key);
278 private void InitRead (XmlTextReader reader)
280 reader.MoveToContent ();
281 if (reader.NodeType != XmlNodeType.Element || reader.Name != "configuration")
282 ThrowException ("Configuration file does not have a valid root element", reader);
284 if (reader.HasAttributes)
285 ThrowException ("Unrecognized attribute in root element", reader);
287 MoveToNextElement (reader);
290 private void MoveToNextElement (XmlTextReader reader)
292 while (reader.Read ()) {
293 XmlNodeType ntype = reader.NodeType;
294 if (ntype == XmlNodeType.Element)
297 if (ntype != XmlNodeType.Whitespace &&
298 ntype != XmlNodeType.Comment &&
299 ntype != XmlNodeType.SignificantWhitespace &&
300 ntype != XmlNodeType.EndElement)
301 ThrowException ("Unrecognized element", reader);
305 private void ReadSection (XmlTextReader reader, string sectionName)
308 string nameValue = null;
309 string typeValue = null;
311 while (reader.MoveToNextAttribute ()) {
312 attName = reader.Name;
316 if (attName == "allowLocation" || attName == "allowDefinition")
319 if (attName == "type") {
320 if (typeValue != null)
321 ThrowException ("Duplicated type attribute.", reader);
322 typeValue = reader.Value;
326 if (attName == "name") {
327 if (nameValue != null)
328 ThrowException ("Duplicated name attribute.", reader);
329 nameValue = reader.Value;
333 ThrowException ("Unrecognized attribute.", reader);
336 if (nameValue == null || typeValue == null)
337 ThrowException ("Required attribute missing", reader);
339 if (sectionName != null)
340 nameValue = sectionName + '/' + nameValue;
342 reader.MoveToElement();
343 object o = LookForFactory (nameValue);
344 if (o != null && o != removedMark)
345 ThrowException ("Already have a factory for " + nameValue, reader);
347 factories [nameValue] = typeValue;
348 MoveToNextElement (reader);
351 private void ReadRemoveSection (XmlTextReader reader, string sectionName)
353 if (!reader.MoveToNextAttribute () || reader.Name != "name")
354 ThrowException ("Unrecognized attribute.", reader);
356 string removeValue = reader.Value;
357 if (removeValue == null || removeValue.Length == 0)
358 ThrowException ("Empty name to remove", reader);
360 reader.MoveToElement ();
362 if (sectionName != null)
363 removeValue = sectionName + '/' + removeValue;
365 object o = LookForFactory (removeValue);
366 if (o != null && o == removedMark)
367 ThrowException ("No factory for " + removeValue, reader);
369 factories [removeValue] = removedMark;
370 MoveToNextElement (reader);
373 private void ReadSectionGroup (XmlTextReader reader, string configSection)
375 if (!reader.MoveToNextAttribute ())
376 ThrowException ("sectionGroup must have a 'name' attribute.", reader);
378 if (reader.Name != "name")
379 ThrowException ("Unrecognized attribute.", reader);
381 if (reader.MoveToNextAttribute ())
382 ThrowException ("Unrecognized attribute.", reader);
384 string value = reader.Value;
385 if (configSection != null)
386 value = configSection + '/' + value;
388 object o = LookForFactory (value);
389 if (o != null && o != removedMark)
390 ThrowException ("Already have a factory for " + value, reader);
392 factories [value] = groupMark;
393 MoveToNextElement (reader);
394 ReadSections (reader, value);
397 private void ReadSections (XmlTextReader reader, string configSection)
399 int depth = reader.Depth;
400 while (reader.Depth == depth) {
401 string name = reader.Name;
402 if (name == "section") {
403 ReadSection (reader, configSection);
407 if (name == "remove") {
408 ReadRemoveSection (reader, configSection);
412 if (name == "clear") {
413 if (reader.HasAttributes)
414 ThrowException ("Unrecognized attribute.", reader);
417 MoveToNextElement (reader);
421 if (name == "sectionGroup") {
422 ReadSectionGroup (reader, configSection);
427 ThrowException ("Unrecognized element: " + reader.Name, reader);
431 private void ReadConfigFile (XmlTextReader reader)
433 int depth = reader.Depth;
434 while (reader.Depth == depth) {
435 string name = reader.Name;
436 if (name == "configSections") {
437 if (reader.HasAttributes)
438 ThrowException ("Unrecognized attribute in configSections element.", reader);
439 MoveToNextElement (reader);
440 ReadSections (reader, null);
444 MoveToNextElement (reader);
448 private void ThrowException (string text, XmlTextReader reader)
450 throw new ConfigurationException (text, fileName, reader.LineNumber);