2 // System.Web.Configuration.WebConfigurationManager.cs
5 // Lluis Sanchez Gual (lluis@novell.com)
6 // Chris Toshok (toshok@ximian.com)
8 // Permission is hereby granted, free of charge, to any person obtaining
9 // a copy of this software and associated documentation files (the
10 // "Software"), to deal in the Software without restriction, including
11 // without limitation the rights to use, copy, modify, merge, publish,
12 // distribute, sublicense, and/or sell copies of the Software, and to
13 // permit persons to whom the Software is furnished to do so, subject to
14 // the following conditions:
16 // The above copyright notice and this permission notice shall be
17 // included in all copies or substantial portions of the Software.
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
34 using System.Collections;
35 using System.Collections.Specialized;
36 using System.Reflection;
41 using System.Configuration;
42 using System.Configuration.Internal;
43 using _Configuration = System.Configuration.Configuration;
44 using System.Web.Util;
46 namespace System.Web.Configuration {
48 public static class WebConfigurationManager
51 static IInternalConfigConfigurationFactory configFactory;
52 static Hashtable configurations = Hashtable.Synchronized (new Hashtable ());
53 static Hashtable sectionCache = new Hashtable ();
54 static Hashtable configPaths = Hashtable.Synchronized (new Hashtable ());
56 const string AppSettingsKey = "WebConfigurationManager.AppSettings";
57 static internal IInternalConfigConfigurationFactory configFactory
60 IInternalConfigConfigurationFactory factory = (IInternalConfigConfigurationFactory)AppDomain.CurrentDomain.GetData("WebConfigurationManager.configFactory");
62 lock (AppDomain.CurrentDomain){
63 object initialized = AppDomain.CurrentDomain.GetData("WebConfigurationManager.configFactory.initialized");
64 if (initialized == null){
65 PropertyInfo prop = typeof(ConfigurationManager).GetProperty("ConfigurationFactory", BindingFlags.Static | BindingFlags.NonPublic);
67 factory = prop.GetValue(null, null) as IInternalConfigConfigurationFactory;
68 configFactory = factory;
73 return factory != null ? factory : configFactory;
76 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configFactory", value);
77 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configFactory.initialized", true);
81 static internal Hashtable configurations
84 Hashtable table = (Hashtable)AppDomain.CurrentDomain.GetData("WebConfigurationManager.configurations");
86 lock (AppDomain.CurrentDomain){
87 object initialized = AppDomain.CurrentDomain.GetData("WebConfigurationManager.configurations.initialized");
88 if (initialized == null){
89 table = Hashtable.Synchronized (new Hashtable (StringComparer.OrdinalIgnoreCase));
90 configurations = table;
94 return table != null ? table : configurations;
98 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configurations", value);
99 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configurations.initialized", true);
103 static Hashtable sectionCache
107 Hashtable sectionCache = (Hashtable) AppDomain.CurrentDomain.GetData ("sectionCache");
108 if (sectionCache == null) {
109 sectionCache = new Hashtable (StringComparer.OrdinalIgnoreCase);
110 AppDomain.CurrentDomain.SetData ("sectionCache", sectionCache);
116 AppDomain.CurrentDomain.SetData ("sectionCache", value);
120 static internal Hashtable configPaths
123 Hashtable table = (Hashtable)AppDomain.CurrentDomain.GetData("WebConfigurationManager.configPaths");
125 lock (AppDomain.CurrentDomain){
126 object initialized = AppDomain.CurrentDomain.GetData("WebConfigurationManager.configPaths.initialized");
127 if (initialized == null){
128 table = Hashtable.Synchronized (new Hashtable (StringComparer.OrdinalIgnoreCase));
133 return table != null ? table : configPaths;
137 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configPaths", value);
138 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configPaths.initialized", true);
143 static ArrayList extra_assemblies = null;
144 static internal ArrayList ExtraAssemblies {
146 if (extra_assemblies == null)
147 extra_assemblies = new ArrayList();
148 return extra_assemblies;
152 static bool hasConfigErrors = false;
153 static object hasConfigErrorsLock = new object ();
154 static internal bool HasConfigErrors {
156 lock (hasConfigErrorsLock) {
157 return hasConfigErrors;
162 static WebConfigurationManager ()
164 PropertyInfo prop = typeof(ConfigurationManager).GetProperty ("ConfigurationFactory", BindingFlags.Static | BindingFlags.NonPublic);
166 configFactory = prop.GetValue (null, null) as IInternalConfigConfigurationFactory;
168 // Part of fix for bug #491531
169 Type type = Type.GetType ("System.Configuration.CustomizableFileSettingsProvider, System", false);
171 FieldInfo fi = type.GetField ("webConfigurationFileMapType", BindingFlags.Static | BindingFlags.NonPublic);
172 if (fi != null && fi.FieldType == Type.GetType ("System.Type"))
173 fi.SetValue (null, typeof (ApplicationSettingsConfigurationFileMap));
177 public static _Configuration OpenMachineConfiguration ()
179 return ConfigurationManager.OpenMachineConfiguration ();
182 [MonoLimitation ("locationSubPath is not handled")]
183 public static _Configuration OpenMachineConfiguration (string locationSubPath)
185 return OpenMachineConfiguration ();
188 [MonoLimitation("Mono does not support remote configuration")]
189 public static _Configuration OpenMachineConfiguration (string locationSubPath,
193 return OpenMachineConfiguration (locationSubPath);
195 throw new NotSupportedException ("Mono doesn't support remote configuration");
198 [MonoLimitation("Mono does not support remote configuration")]
199 public static _Configuration OpenMachineConfiguration (string locationSubPath,
204 return OpenMachineConfiguration (locationSubPath);
205 throw new NotSupportedException ("Mono doesn't support remote configuration");
208 [MonoLimitation("Mono does not support remote configuration")]
209 public static _Configuration OpenMachineConfiguration (string locationSubPath,
215 return OpenMachineConfiguration (locationSubPath);
216 throw new NotSupportedException ("Mono doesn't support remote configuration");
219 public static _Configuration OpenWebConfiguration (string path)
221 return OpenWebConfiguration (path, null, null, null, null, null);
224 public static _Configuration OpenWebConfiguration (string path, string site)
226 return OpenWebConfiguration (path, site, null, null, null, null);
229 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath)
231 return OpenWebConfiguration (path, site, locationSubPath, null, null, null);
234 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server)
236 return OpenWebConfiguration (path, site, locationSubPath, server, null, null);
239 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, IntPtr userToken)
241 return OpenWebConfiguration (path, site, locationSubPath, server, null, null);
244 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, string userName, string password)
246 return OpenWebConfiguration (path, site, locationSubPath, server, null, null, false);
249 static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, string userName, string password, bool fweb)
251 if (String.IsNullOrEmpty (path))
254 if (!fweb && !String.IsNullOrEmpty (path))
255 path = FindWebConfig (path);
257 string confKey = path + site + locationSubPath + server + userName + password;
258 _Configuration conf = null;
259 conf = (_Configuration) configurations [confKey];
262 conf = ConfigurationFactory.Create (typeof (WebConfigurationHost), null, path, site, locationSubPath, server, userName, password);
263 configurations [confKey] = conf;
264 } catch (Exception ex) {
265 lock (hasConfigErrorsLock) {
266 hasConfigErrors = true;
274 public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path)
276 return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path);
279 public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path, string site)
281 return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path, site);
284 public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path, string site, string locationSubPath)
286 return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path, site, locationSubPath);
289 public static _Configuration OpenMappedMachineConfiguration (ConfigurationFileMap fileMap)
291 return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap);
294 public static _Configuration OpenMappedMachineConfiguration (ConfigurationFileMap fileMap,
295 string locationSubPath)
297 return OpenMappedMachineConfiguration (fileMap);
300 internal static object SafeGetSection (string sectionName, Type configSectionType)
303 return GetSection (sectionName);
304 } catch (Exception) {
305 if (configSectionType != null)
306 return Activator.CreateInstance (configSectionType);
311 internal static object SafeGetSection (string sectionName, string path, Type configSectionType)
314 return GetSection (sectionName, path);
315 } catch (Exception) {
316 if (configSectionType != null)
317 return Activator.CreateInstance (configSectionType);
322 public static object GetSection (string sectionName)
324 HttpContext context = HttpContext.Current;
325 return GetSection (sectionName, GetCurrentPath (context), context);
328 public static object GetSection (string sectionName, string path)
330 return GetSection (sectionName, path, HttpContext.Current);
333 internal static object GetSection (string sectionName, string path, HttpContext context)
335 string config_vdir = FindWebConfig (path);
336 if (String.IsNullOrEmpty (config_vdir))
339 object cachedSection = sectionCache [GetSectionCacheKey (sectionName, config_vdir)];
340 if (cachedSection != null)
341 return cachedSection;
343 HttpRequest req = context != null ? context.Request : null;
344 _Configuration c = OpenWebConfiguration (config_vdir, //path, /* path */
346 req != null ? VirtualPathUtility.GetDirectory (req.Path) : null, /* locationSubPath */
350 true /* path from FindWebConfig */);
351 ConfigurationSection section = c.GetSection (sectionName);
356 object value = get_runtime_object.Invoke (section, new object [0]);
357 if (String.CompareOrdinal ("appSettings", sectionName) == 0) {
358 NameValueCollection collection;
359 collection = new KeyValueMergedCollection (HttpContext.Current, (NameValueCollection) value);
363 AddSectionToCache (GetSectionCacheKey (sectionName, config_vdir), value);
367 object value = SettingsMappingManager.MapSection (get_runtime_object.Invoke (section, new object [0]));
371 AddSectionToCache (GetSectionCacheKey (sectionName, config_vdir), value);
376 static string MapPath (HttpRequest req, string virtualPath)
379 return req.MapPath (virtualPath);
381 string appRoot = HttpRuntime.AppDomainAppVirtualPath;
382 if (!String.IsNullOrEmpty (appRoot) && virtualPath.StartsWith (appRoot, StringComparison.Ordinal)) {
383 if (String.Compare (virtualPath, appRoot, StringComparison.Ordinal) == 0)
384 return HttpRuntime.AppDomainAppPath;
385 return UrlUtils.Combine (HttpRuntime.AppDomainAppPath, virtualPath.Substring (appRoot.Length));
391 static string GetParentDir (string rootPath, string curPath)
393 int len = curPath.Length - 1;
394 if (len > 0 && curPath [len] == '/')
395 curPath = curPath.Substring (0, len);
397 if (String.Compare (curPath, rootPath, StringComparison.Ordinal) == 0)
400 int idx = curPath.LastIndexOf ('/');
407 return curPath.Substring (0, idx);
410 internal static string FindWebConfig (string path)
412 if (String.IsNullOrEmpty (path))
416 if (path [path.Length - 1] == '/')
419 dir = VirtualPathUtility.GetDirectory (path, false);
424 string curPath = configPaths [dir] as string;
428 HttpContext ctx = HttpContext.Current;
429 HttpRequest req = ctx != null ? ctx.Request : null;
434 string rootPath = HttpRuntime.AppDomainAppVirtualPath;
437 while (String.Compare (curPath, rootPath, StringComparison.Ordinal) != 0) {
438 physPath = MapPath (req, curPath);
439 if (physPath == null) {
444 if (WebConfigurationHost.GetWebConfigFileName (physPath) != null)
447 curPath = GetParentDir (rootPath, curPath);
448 if (curPath == null) {
454 configPaths [dir] = curPath;
458 static string GetCurrentPath (HttpContext ctx)
460 HttpRequest req = ctx != null ? ctx.Request : null;
461 return req != null ? req.Path : HttpRuntime.AppDomainAppVirtualPath;
464 internal static void RemoveConfigurationFromCache (HttpContext ctx)
466 configurations.Remove (GetCurrentPath (ctx));
469 #if TARGET_J2EE || MONOWEB_DEP
470 readonly static MethodInfo get_runtime_object = typeof (ConfigurationSection).GetMethod ("GetRuntimeObject", BindingFlags.NonPublic | BindingFlags.Instance);
473 public static object GetWebApplicationSection (string sectionName)
475 HttpContext ctx = HttpContext.Current;
476 HttpRequest req = ctx != null ? ctx.Request : null;
477 string applicationPath = req != null ? req.ApplicationPath : null;
478 return GetSection (sectionName, String.IsNullOrEmpty (applicationPath) ? String.Empty : applicationPath);
481 public static NameValueCollection AppSettings {
482 get { return ConfigurationManager.AppSettings; }
485 public static ConnectionStringSettingsCollection ConnectionStrings {
486 get { return ConfigurationManager.ConnectionStrings; }
489 internal static IInternalConfigConfigurationFactory ConfigurationFactory {
490 get { return configFactory; }
493 static void AddSectionToCache (int key, object section)
495 if (sectionCache [key] != null)
498 Hashtable tmpTable = (Hashtable) sectionCache.Clone ();
499 if (tmpTable.Contains (key))
502 tmpTable.Add (key, section);
503 sectionCache = tmpTable;
506 static int GetSectionCacheKey (string sectionName, string path)
508 return (sectionName != null ? sectionName.GetHashCode () : 0) ^ ((path != null ? path.GetHashCode () : 0) + 37);
512 #region stuff copied from WebConfigurationSettings
514 static internal IConfigurationSystem oldConfig {
516 return (IConfigurationSystem)AppDomain.CurrentDomain.GetData("WebConfigurationManager.oldConfig");
519 AppDomain.CurrentDomain.SetData("WebConfigurationManager.oldConfig", value);
523 static Web20DefaultConfig config {
525 return (Web20DefaultConfig) AppDomain.CurrentDomain.GetData ("Web20DefaultConfig.config");
528 AppDomain.CurrentDomain.SetData ("Web20DefaultConfig.config", value);
532 static IInternalConfigSystem configSystem {
534 return (IInternalConfigSystem) AppDomain.CurrentDomain.GetData ("IInternalConfigSystem.configSystem");
537 AppDomain.CurrentDomain.SetData ("IInternalConfigSystem.configSystem", value);
541 static internal IConfigurationSystem oldConfig;
542 static Web20DefaultConfig config;
543 //static IInternalConfigSystem configSystem;
545 const BindingFlags privStatic = BindingFlags.NonPublic | BindingFlags.Static;
546 static readonly object lockobj = new object ();
548 internal static void Init ()
554 /* deal with the ConfigurationSettings stuff */
556 Web20DefaultConfig settings = Web20DefaultConfig.GetInstance ();
557 Type t = typeof (ConfigurationSettings);
558 MethodInfo changeConfig = t.GetMethod ("ChangeConfigurationSystem",
561 if (changeConfig == null)
562 throw new ConfigurationException ("Cannot find method CCS");
564 object [] args = new object [] {settings};
565 oldConfig = (IConfigurationSystem)changeConfig.Invoke (null, args);
571 /* deal with the ConfigurationManager stuff */
573 HttpConfigurationSystem system = new HttpConfigurationSystem ();
574 Type t = typeof (ConfigurationManager);
575 MethodInfo changeConfig = t.GetMethod ("ChangeConfigurationSystem",
578 if (changeConfig == null)
579 throw new ConfigurationException ("Cannot find method CCS");
581 object [] args = new object [] {system};
582 changeConfig.Invoke (null, args);
583 //configSystem = system;
589 class Web20DefaultConfig : IConfigurationSystem
592 static Web20DefaultConfig instance {
594 Web20DefaultConfig val = (Web20DefaultConfig)AppDomain.CurrentDomain.GetData("Web20DefaultConfig.instance");
596 val = new Web20DefaultConfig();
597 AppDomain.CurrentDomain.SetData("Web20DefaultConfig.instance", val);
602 AppDomain.CurrentDomain.SetData("Web20DefaultConfig.instance", value);
606 static Web20DefaultConfig instance;
609 static Web20DefaultConfig ()
611 instance = new Web20DefaultConfig ();
614 public static Web20DefaultConfig GetInstance ()
619 public object GetConfig (string sectionName)
621 object o = WebConfigurationManager.GetWebApplicationSection (sectionName);
623 if (o == null || o is IgnoreSection) {
624 /* this can happen when the section
625 * handler doesn't subclass from
626 * ConfigurationSection. let's be
627 * nice and try to load it using the
628 * 1.x style routines in case there's
629 * a 1.x section handler registered
632 object o1 = WebConfigurationManager.oldConfig.GetConfig (sectionName);
642 // nothing. We need a context.