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;
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)
83 return config.GetConfig (sectionName);
93 ConfigurationData data = new ConfigurationData ();
94 if (data.Load (GetMachineConfigPath ())) {
95 ConfigurationData appData = new ConfigurationData (data);
96 appData.Load (GetAppConfigPath ());
102 private static string GetMachineConfigPath ()
104 string location = typeof (string).Assembly.Location;
105 // Workaround for bug #31730
106 int index = location.IndexOf ("install");
107 location = Path.Combine (location.Substring (0, index + 7), "lib");
109 return Path.Combine (location, "machine.config");
112 private static string GetAppConfigPath ()
114 AppDomainSetup currentInfo = AppDomain.CurrentDomain.SetupInformation;
116 string appBase = currentInfo.ApplicationBase;
117 string configFile = currentInfo.ConfigurationFile;
118 // FIXME: need to check out default domain configuration file name
119 if (configFile == null || configFile.Length == 0)
122 return Path.Combine (appBase, configFile);
126 class ConfigurationData
128 ConfigurationData parent;
131 object removedMark = new object ();
132 object groupMark = new object ();
134 public ConfigurationData () : this (null)
138 public ConfigurationData (ConfigurationData parent)
140 this.parent = parent;
141 factories = new Hashtable ();
144 public bool Load (string fileName)
146 if (fileName == null)
149 this.fileName = fileName;
150 XmlTextReader reader = null;
153 reader = new XmlTextReader (fileName);
155 MoveToNextElement (reader);
156 ReadSections (reader, null);
165 IConfigurationSectionHandler GetSectionHandler (string sectionName)
167 if (!factories.Contains (sectionName)) {
171 return parent.GetConfig (sectionName) as IConfigurationSectionHandler;
174 object o = factories [sectionName];
175 if (o == removedMark)
178 if (o is IConfigurationSectionHandler)
179 return (IConfigurationSectionHandler) o;
181 Type iconfig = typeof (IConfigurationSectionHandler);
182 string [] typeInfo = ((string) o).Split (',');
185 // Hack. Type.GetType should be enough
186 if (typeInfo.Length > 1) {
187 Assembly ass = Assembly.Load (typeInfo [1].Trim ());
188 t = ass.GetType (typeInfo [0].Trim ());
190 t = Type.GetType (typeInfo [0]);
194 throw new ConfigurationException ("Cannot get Type for " + o);
196 if (!iconfig.IsAssignableFrom (t))
197 throw new ConfigurationException (sectionName + " does not implement " + iconfig);
199 o = Activator.CreateInstance (t, true);
201 throw new ConfigurationException ("Cannot get instance for " + t);
203 return (IConfigurationSectionHandler) o;
206 //TODO: Should use XPath when it works properly for this.
207 XmlDocument GetDocumentForSection (string sectionName)
209 ConfigXmlDocument doc = new ConfigXmlDocument ();
210 XmlTextReader reader = new XmlTextReader (fileName);
212 string [] sectionPath = sectionName.Split ('/');
216 while (!reader.EOF) {
217 if (reader.NodeType == XmlNodeType.Element &&
218 reader.Name == sectionPath [i]) {
219 if (++i == sectionPath.Length) {
220 doc.LoadSingleElement (fileName, reader);
223 MoveToNextElement (reader);
227 if (reader.NodeType != XmlNodeType.Element)
228 MoveToNextElement (reader);
236 public object GetConfig (string sectionName)
238 IConfigurationSectionHandler handler = GetSectionHandler (sectionName);
242 factories [sectionName] = handler;
244 XmlDocument doc = GetDocumentForSection (sectionName);
246 throw new ConfigurationException ("Section not found: " + sectionName);
248 return handler.Create (null, null, doc);
251 private object LookForFactory (string key)
253 object o = factories [key];
258 return parent.LookForFactory (key);
263 private void InitRead (XmlTextReader reader)
265 reader.MoveToContent ();
266 if (reader.NodeType != XmlNodeType.Element || reader.Name != "configuration")
267 ThrowException ("Configuration file does not have a valid root element", reader);
269 if (reader.HasAttributes)
270 ThrowException ("Unrecognized attribute in root element", reader);
272 MoveToNextElement (reader);
273 if (reader.Depth == 1 && reader.Name == "configSections") {
274 if (reader.HasAttributes)
275 ThrowException ("Unrecognized attribute in configSections element.",
280 private void MoveToNextElement (XmlTextReader reader)
282 while (reader.Read ()) {
283 XmlNodeType ntype = reader.NodeType;
284 if (ntype == XmlNodeType.Element)
287 if (ntype != XmlNodeType.Whitespace &&
288 ntype != XmlNodeType.Comment &&
289 ntype != XmlNodeType.SignificantWhitespace &&
290 ntype != XmlNodeType.EndElement)
291 ThrowException ("Unrecognized element", reader);
295 private void ReadSection (XmlTextReader reader, string sectionName)
298 string nameValue = null;
299 string typeValue = null;
301 while (reader.MoveToNextAttribute ()) {
302 attName = reader.Name;
306 if (attName == "allowLocation" || attName == "allowDefinition")
309 if (attName == "type") {
310 if (typeValue != null)
311 ThrowException ("Duplicated type attribute.", reader);
312 typeValue = reader.Value;
316 if (attName == "name") {
317 if (nameValue != null)
318 ThrowException ("Duplicated name attribute.", reader);
319 nameValue = reader.Value;
323 ThrowException ("Unrecognized attribute.", reader);
326 if (nameValue == null || typeValue == null)
327 ThrowException ("Required attribute missing", reader);
329 if (sectionName != null)
330 nameValue = sectionName + '/' + nameValue;
332 reader.MoveToElement();
333 object o = LookForFactory (nameValue);
334 if (o != null && o != removedMark)
335 ThrowException ("Already have a factory for " + nameValue, reader);
337 factories [nameValue] = typeValue;
338 MoveToNextElement (reader);
341 private void ReadRemoveSection (XmlTextReader reader, string sectionName)
343 if (!reader.MoveToNextAttribute () || reader.Name != "name")
344 ThrowException ("Unrecognized attribute.", reader);
346 string removeValue = reader.Value;
347 if (removeValue == null || removeValue.Length == 0)
348 ThrowException ("Empty name to remove", reader);
350 reader.MoveToElement ();
352 if (sectionName != null)
353 removeValue = sectionName + '/' + removeValue;
355 object o = LookForFactory (removeValue);
356 if (o != null && o != removedMark)
357 ThrowException ("No factory for " + removeValue, reader);
359 factories [removeValue] = removedMark;
360 MoveToNextElement (reader);
363 private void ReadSectionGroup (XmlTextReader reader, string configSection)
365 if (!reader.MoveToNextAttribute ())
366 ThrowException ("sectionGroup must have a 'name' attribute.", reader);
368 if (reader.Name != "name")
369 ThrowException ("Unrecognized attribute.", reader);
371 if (reader.MoveToNextAttribute ())
372 ThrowException ("Unrecognized attribute.", reader);
374 string value = reader.Value;
375 if (configSection != null)
376 value = configSection + '/' + value;
378 object o = LookForFactory (value);
379 if (o != null && o != removedMark)
380 ThrowException ("Already have a factory for " + value, reader);
382 factories [value] = groupMark;
383 MoveToNextElement (reader);
384 ReadSections (reader, value);
387 private void ReadSections (XmlTextReader reader, string configSection)
389 int depth = reader.Depth;
390 while (reader.Depth == depth) {
391 string name = reader.Name;
392 if (reader.Name == null)
395 if (name == "section") {
396 ReadSection (reader, configSection);
400 if (name == "remove") {
401 ReadRemoveSection (reader, configSection);
405 if (name == "clear") {
406 if (reader.HasAttributes)
407 ThrowException ("Unrecognized attribute.", reader);
413 if (name == "sectionGroup") {
414 ReadSectionGroup (reader, configSection);
418 ThrowException ("Unrecognized element", reader);
422 private void ThrowException (string text, XmlTextReader reader)
424 throw new ConfigurationException (text, fileName, reader.LineNumber);