+2006-01-26 Chris Toshok <toshok@ximian.com>
+
+ * SectionGroupInfo.cs (ReadContent): handle "location" (seemingly)
+ correctly.
+
+ * InternalConfigurationRoot.cs: misc logical additions. still
+ isn't useful.
+
+ * ConfigurationManager.cs (OpenExeConfigurationInternal): throw an
+ exception if both calling_assembly and exePath are null. Allow
+ the exePath to be a path to a config file as well, checking to see
+ if it ends in .config before appending.
+ (OpenExeConfiguration): stop blindly passing
+ Assembly.GetCallingAssembly. I'm assuming this will likely break
+ .dll.config usage. need to investigate that (and write more unit
+ tests.)
+ (GetSection): call configSystem.GetSection.
+ (RefreshSection): call configSystem.RefreshSection.
+ (ChangeConfigurationSystem): modeled after the
+ ConfigurationSettings System.Web hack - allow
+ WebConfigurationManager to replace the current
+ IInternalConfigSystem.
+
+ * InternalConfigurationHost.cs (InternalConfigurationHost): make
+ abstract, and remove all the NotImplenmentedException's.
+
+ * ConfigurationElement.cs (DeserializeElement): store off the xml
+ namespace if there is one.
+ (SerializeElement): write out the namespace if there was one.
+
+ * ClientConfigurationSystem.cs: new class, based on some stack
+ traces I've seen in tests. Kinda (well, not *kinda*..) hacky.
+
+ * Configuration.cs (NamespaceDeclared): implement.
+ (Load): don't swallow all exceptions, just the ones raised when we
+ open the stream for reading.
+ (ReadConfigFile): handle xmlns.
+
2006-01-25 Chris Toshok <toshok@ximian.com>
* ConfigInfo.cs (ThrowException): throw a
--- /dev/null
+//
+// System.Configuration.ClientConfigurationSystem.cs
+//
+// Authors:
+// Chris Toshok (toshok@ximian.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
+//
+
+#if NET_2_0
+
+using System;
+using System.Reflection;
+using System.Configuration.Internal;
+
+namespace System.Configuration {
+
+ internal class ClientConfigurationSystem : IInternalConfigSystem
+ {
+ object IInternalConfigSystem.GetSection (string configKey)
+ {
+ Assembly a = Assembly.GetEntryAssembly();
+
+ Configuration cfg = ConfigurationManager.OpenExeConfigurationInternal (ConfigurationUserLevel.None, a, AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
+ if (cfg == null) return null;
+ return cfg.GetSection (configKey);
+ }
+
+ void IInternalConfigSystem.RefreshConfig (string sectionName)
+ {
+ }
+
+ /* I'm guessing this means "we support ConfigurationUserLevel.PerUser* files" */
+ bool IInternalConfigSystem.SupportsUserConfig {
+ get { return true; }
+ }
+ }
+}
+
+#endif
SectionGroupInfo rootGroup;
IConfigSystem system;
bool hasFile;
+ string rootNamespace;
string configPath;
string locationConfigPath;
}
}
- [MonoTODO]
public bool NamespaceDeclared {
- get {
- throw new NotImplementedException ();
- }
- set {
- throw new NotImplementedException ();
- }
+ get { return rootNamespace != null; }
+ set { rootNamespace = value ? "http://schemas.microsoft.com/.NetConfiguration/v2.0" : null; }
}
public ConfigurationSectionGroup RootSectionGroup {
tw.Formatting = Formatting.Indented;
try {
tw.WriteStartDocument ();
- tw.WriteStartElement ("configuration");
+ if (rootNamespace != null)
+ tw.WriteStartElement ("configuration", rootNamespace);
+ else
+ tw.WriteStartElement ("configuration");
if (rootGroup.HasConfigContent (this)) {
rootGroup.WriteConfig (this, tw, mode);
}
bool Load ()
{
- if (streamName == null)
+ if (streamName == null || streamName == "")
return true;
XmlTextReader reader = null;
+ Stream stream = null;
+
try {
- Stream stream = system.Host.OpenStreamForRead (streamName);
- reader = new XmlTextReader (stream);
- ReadConfigFile (reader, streamName);
+ stream = system.Host.OpenStreamForRead (streamName);
} catch (Exception e) {
return false;
+ }
+
+ try {
+ reader = new XmlTextReader (stream);
+ ReadConfigFile (reader, streamName);
} finally {
if (reader != null)
reader.Close();
internal void ReadConfigFile (XmlTextReader reader, string fileName)
{
reader.MoveToContent ();
+
if (reader.NodeType != XmlNodeType.Element || reader.Name != "configuration")
ThrowException ("Configuration file does not have a valid root element", reader);
- if (reader.HasAttributes)
- ThrowException ("Unrecognized attribute in root element", reader);
+ if (reader.HasAttributes) {
+ while (reader.MoveToNextAttribute ()) {
+ if (reader.LocalName == "xmlns") {
+ rootNamespace = reader.Value;
+ continue;
+ }
+ ThrowException (String.Format ("Unrecognized attribute '{0}' in root element", reader.LocalName), reader);
+ }
+ }
+
+ reader.MoveToElement ();
if (reader.IsEmptyElement) {
reader.Skip ();
public abstract class ConfigurationElement
{
string rawXml;
+ string elementNamespace;
bool modified;
ElementMap map;
ConfigurationPropertyCollection keyProps;
else if (reader.LocalName == "lockItem") {
LockItem = (reader.Value.ToLower() == "true");
}
+ else if (reader.LocalName == "xmlns") {
+ elementNamespace = reader.Value;
+ }
else if (!OnDeserializeUnrecognizedAttribute (reader.LocalName, reader.Value))
throw new ConfigurationException ("Unrecognized attribute '" + reader.LocalName + "'.");
bool wroteData = false;
+ if (elementNamespace != null) {
+ writer.WriteAttributeString ("xmlns", elementNamespace);
+ wroteData = true;
+ }
+
foreach (PropertyInformation prop in ElementInformation.Properties)
{
if (prop.IsElement || prop.ValueOrigin == PropertyValueOrigin.Default)
public static class ConfigurationManager
{
static InternalConfigurationFactory configFactory = new InternalConfigurationFactory ();
+ static IInternalConfigSystem configSystem = new ClientConfigurationSystem ();
+ static object lockobj = new object ();
[MonoTODO ("Evidence and version still needs work")]
static string GetAssemblyInfo (Assembly a)
return Path.Combine (String.Format ("{0}_{1}", app_name, evidence_str), version);
}
- static Configuration OpenExeConfigurationInternal (ConfigurationUserLevel userLevel, Assembly calling_assembly, string exePath)
+ internal static Configuration OpenExeConfigurationInternal (ConfigurationUserLevel userLevel, Assembly calling_assembly, string exePath)
{
+ if (calling_assembly == null && exePath == null)
+ throw new ArgumentException ("exePath must be specified when not running inside a stand alone exe.");
+
ExeConfigurationFileMap map = new ExeConfigurationFileMap ();
/* Roaming and RoamingAndLocal should be different
switch (userLevel) {
case ConfigurationUserLevel.None:
if (exePath == null)
- exePath = Assembly.GetCallingAssembly ().Location;
+ exePath = calling_assembly.Location;
else if (!File.Exists (exePath))
exePath = "";
- if (exePath != "")
- map.ExeConfigFilename = exePath + ".config";
-
+ if (exePath != "") {
+ if (!exePath.EndsWith (".config"))
+ map.ExeConfigFilename = exePath + ".config";
+ else
+ map.ExeConfigFilename = exePath;
+ }
break;
case ConfigurationUserLevel.PerUserRoaming:
map.RoamingUserConfigFilename = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData), GetAssemblyInfo(calling_assembly));
public static Configuration OpenExeConfiguration (ConfigurationUserLevel userLevel)
{
- return OpenExeConfigurationInternal (userLevel, Assembly.GetCallingAssembly (), Assembly.GetCallingAssembly ().Location);
+ return OpenExeConfigurationInternal (userLevel, Assembly.GetEntryAssembly (), null);
}
public static Configuration OpenExeConfiguration (string exePath)
{
- return OpenExeConfigurationInternal (ConfigurationUserLevel.None, Assembly.GetCallingAssembly (), exePath);
+ return OpenExeConfigurationInternal (ConfigurationUserLevel.None, null, exePath);
}
[MonoTODO ("userLevel")]
get { return configFactory; }
}
- [MonoTODO ("this assembly stuff is probably wrong")]
public static object GetSection (string sectionName)
{
- Assembly a = Assembly.GetEntryAssembly ();
- if (a == null)
- a = Assembly.GetCallingAssembly ();
- Configuration cfg = OpenExeConfigurationInternal (ConfigurationUserLevel.None,
- a, a.Location);
-
- if (cfg == null)
- return null;
-
- return cfg.GetSection (sectionName);
+ return configSystem.GetSection (sectionName);
}
- [MonoTODO]
public static void RefreshSection (string sectionName)
{
+ configSystem.RefreshConfig (sectionName);
}
public static NameValueCollection AppSettings {
public static ConnectionStringSettingsCollection ConnectionStrings {
get {
ConnectionStringsSection connectionStrings = (ConnectionStringsSection) GetSection ("connectionStrings");
-
return connectionStrings.ConnectionStrings;
}
}
+
+ /* invoked from System.Web */
+ static IInternalConfigSystem ChangeConfigurationSystem (IInternalConfigSystem newSystem)
+ {
+ if (newSystem == null)
+ throw new ArgumentNullException ("newSystem");
+
+ lock (lockobj) {
+ IInternalConfigSystem old = configSystem;
+ configSystem = newSystem;
+ return old;
+ }
+ }
}
}
namespace System.Configuration
{
- class InternalConfigurationHost: IInternalConfigHost
+ abstract class InternalConfigurationHost: IInternalConfigHost
{
public virtual object CreateConfigurationContext (string configPath, string locationSubPath)
{
throw new NotImplementedException ();
}
- public virtual string GetStreamName (string configPath)
- {
- throw new NotImplementedException ();
- }
+ public abstract string GetStreamName (string configPath);
+ public abstract void Init (IInternalConfigRoot root, params object[] hostInitParams);
+ public abstract void InitForConfiguration (ref string locationSubPath, out string configPath, out string locationConfigPath, IInternalConfigRoot root, params object[] hostInitConfigurationParams);
+ [MonoTODO ("remote config")]
public virtual string GetStreamNameForConfigSource (string streamName, string configSource)
{
- throw new NotImplementedException ();
+ throw new NotSupportedException ("mono does not support remote configuration");
}
public virtual object GetStreamVersion (string streamName)
throw new NotImplementedException ();
}
- public virtual void Init (IInternalConfigRoot root, params object[] hostInitParams)
- {
- }
-
- public virtual void InitForConfiguration (ref string locationSubPath, out string configPath, out string locationConfigPath, IInternalConfigRoot root, params object[] hostInitConfigurationParams)
- {
- throw new NotImplementedException ();
- }
-
public virtual bool IsAboveApplication (string configPath)
{
throw new NotImplementedException ();
{
class InternalConfigurationRoot: IInternalConfigRoot
{
+ IInternalConfigHost host;
+ bool isDesignTime;
+
+ public InternalConfigurationRoot ()
+ {
+ }
+
+ [MonoTODO]
public IInternalConfigRecord GetConfigRecord (string configPath)
{
throw new NotImplementedException ();
public object GetSection (string section, string configPath)
{
- throw new NotImplementedException ();
+ IInternalConfigRecord rec = GetConfigRecord (configPath);
+ return rec.GetSection (section);
}
-
+
+ [MonoTODO]
public string GetUniqueConfigPath (string configPath)
{
- throw new NotImplementedException ();
+ return configPath;
}
-
+
+ [MonoTODO]
public IInternalConfigRecord GetUniqueConfigRecord (string configPath)
{
- throw new NotImplementedException ();
+ return GetConfigRecord (GetUniqueConfigPath (configPath));
}
public void Init (IInternalConfigHost host, bool isDesignTime)
{
+ this.host = host;
+ this.isDesignTime = isDesignTime;
}
-
+
+ [MonoTODO]
public void RemoveConfig (string configPath)
{
+ host.DeleteStream (configPath);
+
if (ConfigRemoved != null)
ConfigRemoved (this, new InternalConfigEventArgs (configPath));
-
- throw new NotImplementedException ();
}
public bool IsDesignTime {
- get {
- throw new NotImplementedException ();
- }
+ get { return isDesignTime; }
}
public event InternalConfigEventHandler ConfigChanged;
public void ReadRootData (XmlTextReader reader, Configuration config, bool overrideAllowed)
{
reader.MoveToContent ();
- ReadContent (reader, config, overrideAllowed);
+ ReadContent (reader, config, overrideAllowed, true);
}
public override void ReadData (Configuration config, XmlTextReader reader, bool overrideAllowed)
{
reader.MoveToContent ();
reader.ReadStartElement ();
- ReadContent (reader, config, overrideAllowed);
+ ReadContent (reader, config, overrideAllowed, false);
reader.MoveToContent ();
reader.ReadEndElement ();
}
- void ReadContent (XmlTextReader reader, Configuration config, bool overrideAllowed)
+ void ReadContent (XmlTextReader reader, Configuration config, bool overrideAllowed, bool root)
{
StringBuilder spacing = new StringBuilder ();
while (reader.NodeType != XmlNodeType.EndElement) {
continue;
}
- if (reader.LocalName == "location")
- ThrowException ("<location> elements are only allowed in <configuration> elements.", reader);
+ if (reader.LocalName == "location") {
+ if (!root)
+ ThrowException ("<location> elements are only allowed in <configuration> elements.", reader);
+
+ string allowOverrideAttr = reader.GetAttribute ("allowOverride");
+ bool allowOverride = allowOverrideAttr == null || allowOverrideAttr.Length == 0 || bool.Parse (allowOverrideAttr);
+ string path = reader.GetAttribute ("path");
+ if (path != null && path.Length > 0) {
+ string xml = reader.ReadOuterXml ();
+ string[] pathList = path.Split (',');
+ foreach (string p in pathList) {
+ ConfigurationLocation loc = new ConfigurationLocation (p.Trim (), xml, config, allowOverride);
+ config.Locations.Add (loc);
+ }
+ } else {
+ ReadData (config, reader, allowOverride);
+ }
+ continue;
+ }
+
ConfigInfo data = (sections != null) ? (ConfigInfo) sections [reader.LocalName] : (ConfigInfo) null;
if (data == null) data = (groups != null) ? (ConfigInfo) groups [reader.LocalName] : (ConfigInfo) null;