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.Reflection;
17 using System.Runtime.CompilerServices;
19 using System.Xml.XPath;
21 namespace System.Configuration
23 public sealed class ConfigurationSettings
25 static IConfigurationSystem config;
27 private ConfigurationSettings ()
31 public static object GetConfig (string sectionName)
34 config = DefaultConfig.GetInstance ();
36 return config.GetConfig (sectionName);
39 public static NameValueCollection AppSettings
42 object appSettings = GetConfig ("appSettings");
43 if (appSettings == null)
44 appSettings = new NameValueCollection ();
46 return (NameValueCollection) appSettings;
53 // class DefaultConfig: read configuration from machine.config file and application
54 // config file if available.
56 class DefaultConfig : IConfigurationSystem
58 static string creatingInstance = "137213797382-asad";
59 static string buildingData = "1797382-ladgasjkdg";
60 static DefaultConfig instance;
61 ConfigurationData config;
63 private DefaultConfig ()
67 public static DefaultConfig GetInstance ()
69 if (instance == null) {
70 lock (creatingInstance) {
71 if (instance == null) {
72 instance = new DefaultConfig ();
82 public object GetConfig (string sectionName)
87 return config.GetConfig (sectionName);
97 ConfigurationData data = new ConfigurationData ();
98 if (data.Load (GetMachineConfigPath ())) {
99 ConfigurationData appData = new ConfigurationData (data);
100 appData.Load (GetAppConfigPath ());
103 Console.WriteLine ("** Warning **: cannot find " + GetMachineConfigPath ());
104 Console.WriteLine ("Trying to load app config file...");
105 data.Load (GetAppConfigPath ());
112 [MethodImplAttribute(MethodImplOptions.InternalCall)]
113 extern private static string get_machine_config_path ();
115 private static string GetMachineConfigPath ()
117 return get_machine_config_path ();
120 private static string GetAppConfigPath ()
122 /* FIXME: Uncomment and use this stuff when the current domain is initialized with
123 the appropiate information.
124 AppDomainSetup currentInfo = AppDomain.CurrentDomain.SetupInformation;
126 string appBase = currentInfo.ApplicationBase;
127 string configFile = currentInfo.ConfigurationFile;
128 // FIXME: need to check out default domain configuration file name
129 if (configFile == null || configFile.Length == 0)
133 // Remove when uncomment the previous comment
134 string assemblyName = Assembly.GetEntryAssembly ().Location;
135 string appBase = Path.GetDirectoryName (assemblyName);
136 string configFile = Path.GetFileName (assemblyName) + ".exe.config";
139 return Path.Combine (appBase, configFile);
144 class ConfigurationData
146 ConfigurationData parent;
149 object removedMark = new object ();
150 object groupMark = new object ();
152 public ConfigurationData () : this (null)
156 public ConfigurationData (ConfigurationData parent)
158 this.parent = (parent == this) ? null : parent;
159 factories = new Hashtable ();
162 public bool Load (string fileName)
164 if (fileName == null)
167 this.fileName = fileName;
168 XmlTextReader reader = null;
172 reader = new XmlTextReader (fileName);
178 ReadConfigFile (reader);
187 object GetHandler (string sectionName)
189 object o = factories [sectionName];
190 if (o == null || o == removedMark) {
192 return parent.GetHandler (sectionName);
197 if (o is IConfigurationSectionHandler)
198 return (IConfigurationSectionHandler) o;
200 string [] typeInfo = ((string) o).Split (',');
203 // Hack. Type.GetType should be enough
204 if (typeInfo.Length > 1) {
205 Assembly ass = Assembly.Load (typeInfo [1].Trim ());
206 t = ass.GetType (typeInfo [0].Trim ());
208 t = Type.GetType (typeInfo [0]);
212 throw new ConfigurationException ("Cannot get Type for " + o);
214 Type iconfig = typeof (IConfigurationSectionHandler);
215 if (!iconfig.IsAssignableFrom (t))
216 throw new ConfigurationException (sectionName + " does not implement " + iconfig);
218 o = Activator.CreateInstance (t, true);
220 throw new ConfigurationException ("Cannot get instance for " + t);
222 factories [sectionName] = o;
227 //TODO: Should use XPath when it works properly for this.
228 XmlDocument GetDocumentForSection (string sectionName)
230 ConfigXmlDocument doc = new ConfigXmlDocument ();
231 XmlTextReader reader = null;
233 reader = new XmlTextReader (fileName);
239 string [] sectionPath = sectionName.Split ('/');
242 if (reader.Name == "configSections")
244 while (!reader.EOF) {
245 if (reader.NodeType == XmlNodeType.Element &&
246 reader.Name == sectionPath [i]) {
247 if (++i == sectionPath.Length) {
248 doc.LoadSingleElement (fileName, reader);
251 MoveToNextElement (reader);
255 if (reader.NodeType != XmlNodeType.Element)
256 MoveToNextElement (reader);
264 public object GetConfig (string sectionName)
266 object handler = GetHandler (sectionName);
270 if (!(handler is IConfigurationSectionHandler))
273 object parentConfig = null;
275 parentConfig = parent.GetConfig (sectionName);
277 XmlDocument doc = GetDocumentForSection (sectionName);
279 if (parentConfig == null)
285 return ((IConfigurationSectionHandler) handler).Create (parentConfig, null, doc);
288 private object LookForFactory (string key)
290 object o = factories [key];
295 return parent.LookForFactory (key);
300 private void InitRead (XmlTextReader reader)
302 reader.MoveToContent ();
303 if (reader.NodeType != XmlNodeType.Element || reader.Name != "configuration")
304 ThrowException ("Configuration file does not have a valid root element", reader);
306 if (reader.HasAttributes)
307 ThrowException ("Unrecognized attribute in root element", reader);
309 MoveToNextElement (reader);
312 private void MoveToNextElement (XmlTextReader reader)
314 while (reader.Read ()) {
315 XmlNodeType ntype = reader.NodeType;
316 if (ntype == XmlNodeType.Element)
319 if (ntype != XmlNodeType.Whitespace &&
320 ntype != XmlNodeType.Comment &&
321 ntype != XmlNodeType.SignificantWhitespace &&
322 ntype != XmlNodeType.EndElement)
323 ThrowException ("Unrecognized element", reader);
327 private void ReadSection (XmlTextReader reader, string sectionName)
330 string nameValue = null;
331 string typeValue = null;
333 while (reader.MoveToNextAttribute ()) {
334 attName = reader.Name;
338 if (attName == "allowLocation" || attName == "allowDefinition")
341 if (attName == "type") {
342 if (typeValue != null)
343 ThrowException ("Duplicated type attribute.", reader);
344 typeValue = reader.Value;
348 if (attName == "name") {
349 if (nameValue != null)
350 ThrowException ("Duplicated name attribute.", reader);
351 nameValue = reader.Value;
355 ThrowException ("Unrecognized attribute.", reader);
358 if (nameValue == null || typeValue == null)
359 ThrowException ("Required attribute missing", reader);
361 if (sectionName != null)
362 nameValue = sectionName + '/' + nameValue;
364 reader.MoveToElement();
365 object o = LookForFactory (nameValue);
366 if (o != null && o != removedMark)
367 ThrowException ("Already have a factory for " + nameValue, reader);
369 factories [nameValue] = typeValue;
370 MoveToNextElement (reader);
373 private void ReadRemoveSection (XmlTextReader reader, string sectionName)
375 if (!reader.MoveToNextAttribute () || reader.Name != "name")
376 ThrowException ("Unrecognized attribute.", reader);
378 string removeValue = reader.Value;
379 if (removeValue == null || removeValue.Length == 0)
380 ThrowException ("Empty name to remove", reader);
382 reader.MoveToElement ();
384 if (sectionName != null)
385 removeValue = sectionName + '/' + removeValue;
387 object o = LookForFactory (removeValue);
388 if (o != null && o != removedMark)
389 ThrowException ("No factory for " + removeValue, reader);
391 factories [removeValue] = removedMark;
392 MoveToNextElement (reader);
395 private void ReadSectionGroup (XmlTextReader reader, string configSection)
397 if (!reader.MoveToNextAttribute ())
398 ThrowException ("sectionGroup must have a 'name' attribute.", reader);
400 if (reader.Name != "name")
401 ThrowException ("Unrecognized attribute.", reader);
403 if (reader.MoveToNextAttribute ())
404 ThrowException ("Unrecognized attribute.", reader);
406 string value = reader.Value;
407 if (configSection != null)
408 value = configSection + '/' + value;
410 object o = LookForFactory (value);
411 if (o != null && o != removedMark)
412 ThrowException ("Already have a factory for " + value, reader);
414 factories [value] = groupMark;
415 MoveToNextElement (reader);
416 ReadSections (reader, value);
419 private void ReadSections (XmlTextReader reader, string configSection)
421 int depth = reader.Depth;
422 while (reader.Depth == depth) {
423 string name = reader.Name;
424 if (name == "section") {
425 ReadSection (reader, configSection);
429 if (name == "remove") {
430 ReadRemoveSection (reader, configSection);
434 if (name == "clear") {
435 if (reader.HasAttributes)
436 ThrowException ("Unrecognized attribute.", reader);
439 MoveToNextElement (reader);
443 if (name == "sectionGroup") {
444 ReadSectionGroup (reader, configSection);
449 ThrowException ("Unrecognized element: " + reader.Name, reader);
453 private void ReadConfigFile (XmlTextReader reader)
455 int depth = reader.Depth;
456 while (reader.Depth == depth) {
457 string name = reader.Name;
458 if (name == "configSections") {
459 if (reader.HasAttributes)
460 ThrowException ("Unrecognized attribute in configSections element.", reader);
461 MoveToNextElement (reader);
462 ReadSections (reader, null);
466 MoveToNextElement (reader);
470 private void ThrowException (string text, XmlTextReader reader)
472 throw new ConfigurationException (text, fileName, reader.LineNumber);