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 XmlTextReader reader = null;
210 reader = new XmlTextReader (fileName);
215 ConfigXmlDocument doc = new ConfigXmlDocument ();
217 string [] sectionPath = sectionName.Split ('/');
220 if (reader.Name == "configSections")
223 while (!reader.EOF) {
224 if (reader.NodeType == XmlNodeType.Element &&
225 reader.Name == sectionPath [i]) {
226 if (++i == sectionPath.Length) {
227 doc.LoadSingleElement (fileName, reader);
230 MoveToNextElement (reader);
234 if (reader.NodeType != XmlNodeType.Element)
235 MoveToNextElement (reader);
243 public object GetConfig (string sectionName)
245 object handler = GetHandler (sectionName);
249 if (!(handler is IConfigurationSectionHandler))
252 object parentConfig = null;
254 parentConfig = parent.GetConfig (sectionName);
256 XmlDocument doc = GetDocumentForSection (sectionName);
257 if (doc == null || doc.DocumentElement == null) {
258 if (parentConfig == null)
264 return ((IConfigurationSectionHandler) handler).Create (parentConfig, null, doc.DocumentElement);
267 private object LookForFactory (string key)
269 object o = factories [key];
274 return parent.LookForFactory (key);
279 private void InitRead (XmlTextReader reader)
281 reader.MoveToContent ();
282 if (reader.NodeType != XmlNodeType.Element || reader.Name != "configuration")
283 ThrowException ("Configuration file does not have a valid root element", reader);
285 if (reader.HasAttributes)
286 ThrowException ("Unrecognized attribute in root element", reader);
288 MoveToNextElement (reader);
291 private void MoveToNextElement (XmlTextReader reader)
293 while (reader.Read ()) {
294 XmlNodeType ntype = reader.NodeType;
295 if (ntype == XmlNodeType.Element)
298 if (ntype != XmlNodeType.Whitespace &&
299 ntype != XmlNodeType.Comment &&
300 ntype != XmlNodeType.SignificantWhitespace &&
301 ntype != XmlNodeType.EndElement)
302 ThrowException ("Unrecognized element", reader);
306 private void ReadSection (XmlTextReader reader, string sectionName)
309 string nameValue = null;
310 string typeValue = null;
312 while (reader.MoveToNextAttribute ()) {
313 attName = reader.Name;
317 if (attName == "allowLocation" || attName == "allowDefinition")
320 if (attName == "type") {
321 if (typeValue != null)
322 ThrowException ("Duplicated type attribute.", reader);
323 typeValue = reader.Value;
327 if (attName == "name") {
328 if (nameValue != null)
329 ThrowException ("Duplicated name attribute.", reader);
330 nameValue = reader.Value;
334 ThrowException ("Unrecognized attribute.", reader);
337 if (nameValue == null || typeValue == null)
338 ThrowException ("Required attribute missing", reader);
340 if (sectionName != null)
341 nameValue = sectionName + '/' + nameValue;
343 reader.MoveToElement();
344 object o = LookForFactory (nameValue);
345 if (o != null && o != removedMark)
346 ThrowException ("Already have a factory for " + nameValue, reader);
348 factories [nameValue] = typeValue;
349 MoveToNextElement (reader);
352 private void ReadRemoveSection (XmlTextReader reader, string sectionName)
354 if (!reader.MoveToNextAttribute () || reader.Name != "name")
355 ThrowException ("Unrecognized attribute.", reader);
357 string removeValue = reader.Value;
358 if (removeValue == null || removeValue.Length == 0)
359 ThrowException ("Empty name to remove", reader);
361 reader.MoveToElement ();
363 if (sectionName != null)
364 removeValue = sectionName + '/' + removeValue;
366 object o = LookForFactory (removeValue);
367 if (o != null && o == removedMark)
368 ThrowException ("No factory for " + removeValue, reader);
370 factories [removeValue] = removedMark;
371 MoveToNextElement (reader);
374 private void ReadSectionGroup (XmlTextReader reader, string configSection)
376 if (!reader.MoveToNextAttribute ())
377 ThrowException ("sectionGroup must have a 'name' attribute.", reader);
379 if (reader.Name != "name")
380 ThrowException ("Unrecognized attribute.", reader);
382 if (reader.MoveToNextAttribute ())
383 ThrowException ("Unrecognized attribute.", reader);
385 string value = reader.Value;
386 if (configSection != null)
387 value = configSection + '/' + value;
389 object o = LookForFactory (value);
390 if (o != null && o != removedMark)
391 ThrowException ("Already have a factory for " + value, reader);
393 factories [value] = groupMark;
394 MoveToNextElement (reader);
395 ReadSections (reader, value);
398 private void ReadSections (XmlTextReader reader, string configSection)
400 int depth = reader.Depth;
401 while (reader.Depth == depth) {
402 string name = reader.Name;
403 if (name == "section") {
404 ReadSection (reader, configSection);
408 if (name == "remove") {
409 ReadRemoveSection (reader, configSection);
413 if (name == "clear") {
414 if (reader.HasAttributes)
415 ThrowException ("Unrecognized attribute.", reader);
418 MoveToNextElement (reader);
422 if (name == "sectionGroup") {
423 ReadSectionGroup (reader, configSection);
428 ThrowException ("Unrecognized element: " + reader.Name, reader);
432 private void ReadConfigFile (XmlTextReader reader)
434 int depth = reader.Depth;
435 while (reader.Depth == depth) {
436 string name = reader.Name;
437 if (name == "configSections") {
438 if (reader.HasAttributes)
439 ThrowException ("Unrecognized attribute in configSections element.", reader);
440 MoveToNextElement (reader);
441 ReadSections (reader, null);
445 MoveToNextElement (reader);
449 private void ThrowException (string text, XmlTextReader reader)
451 throw new ConfigurationException (text, fileName, reader.LineNumber);