Backport of some changes from svn trunk - performance improvement and a fix for bug...
[mono-project.git] / mcs / class / System.Web / System.Web.Configuration_2.0 / WebConfigurationManager.cs
blob8470fb909f2351c7584087b3fc1f126ca69fb97f
1 //
2 // System.Web.Configuration.WebConfigurationManager.cs
3 //
4 // Authors:
5 // Lluis Sanchez Gual (lluis@novell.com)
6 // Chris Toshok (toshok@ximian.com)
7 //
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:
15 //
16 // The above copyright notice and this permission notice shall be
17 // included in all copies or substantial portions of the Software.
18 //
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)
30 #if NET_2_0
32 using System;
33 using System.IO;
34 using System.Collections;
35 using System.Collections.Specialized;
36 using System.Reflection;
37 using System.Web.Util;
38 using System.Xml;
39 using System.Configuration;
40 using System.Configuration.Internal;
41 using _Configuration = System.Configuration.Configuration;
43 namespace System.Web.Configuration {
45 public static class WebConfigurationManager
47 #if !TARGET_J2EE
48 static IInternalConfigConfigurationFactory configFactory;
49 static Hashtable configurations = Hashtable.Synchronized (new Hashtable ());
50 static Hashtable sectionCache = new Hashtable (StringComparer.OrdinalIgnoreCase);
51 #else
52 const string AppSettingsKey = "WebConfigurationManager.AppSettings";
53 static internal IInternalConfigConfigurationFactory configFactory
55 get{
56 IInternalConfigConfigurationFactory factory = (IInternalConfigConfigurationFactory)AppDomain.CurrentDomain.GetData("WebConfigurationManager.configFactory");
57 if (factory == null){
58 lock (AppDomain.CurrentDomain){
59 object initialized = AppDomain.CurrentDomain.GetData("WebConfigurationManager.configFactory.initialized");
60 if (initialized == null){
61 PropertyInfo prop = typeof(ConfigurationManager).GetProperty("ConfigurationFactory", BindingFlags.Static | BindingFlags.NonPublic);
62 if (prop != null){
63 factory = prop.GetValue(null, null) as IInternalConfigConfigurationFactory;
64 configFactory = factory;
69 return factory != null ? factory : configFactory;
71 set{
72 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configFactory", value);
73 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configFactory.initialized", true);
77 static internal Hashtable configurations
79 get{
80 Hashtable table = (Hashtable)AppDomain.CurrentDomain.GetData("WebConfigurationManager.configurations");
81 if (table == null){
82 lock (AppDomain.CurrentDomain){
83 object initialized = AppDomain.CurrentDomain.GetData("WebConfigurationManager.configurations.initialized");
84 if (initialized == null){
85 table = Hashtable.Synchronized (new Hashtable (StringComparer.OrdinalIgnoreCase));
86 configurations = table;
90 return table != null ? table : configurations;
93 set{
94 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configurations", value);
95 AppDomain.CurrentDomain.SetData("WebConfigurationManager.configurations.initialized", true);
99 static Hashtable sectionCache
103 Hashtable sectionCache = (Hashtable) AppDomain.CurrentDomain.GetData ("sectionCache");
104 if (sectionCache == null) {
105 sectionCache = new Hashtable (StringComparer.OrdinalIgnoreCase);
106 AppDomain.CurrentDomain.SetData ("sectionCache", sectionCache);
108 return sectionCache;
112 AppDomain.CurrentDomain.SetData ("sectionCache", value);
115 #endif
117 static ArrayList extra_assemblies = null;
118 static internal ArrayList ExtraAssemblies {
119 get {
120 if (extra_assemblies == null)
121 extra_assemblies = new ArrayList();
122 return extra_assemblies;
126 static bool hasConfigErrors = false;
127 static object hasConfigErrorsLock = new object ();
128 static internal bool HasConfigErrors {
129 get {
130 lock (hasConfigErrorsLock) {
131 return hasConfigErrors;
136 static WebConfigurationManager ()
138 PropertyInfo prop = typeof(ConfigurationManager).GetProperty ("ConfigurationFactory", BindingFlags.Static | BindingFlags.NonPublic);
139 if (prop != null)
140 configFactory = prop.GetValue (null, null) as IInternalConfigConfigurationFactory;
143 public static _Configuration OpenMachineConfiguration ()
145 return ConfigurationManager.OpenMachineConfiguration ();
148 [MonoLimitation ("locationSubPath is not handled")]
149 public static _Configuration OpenMachineConfiguration (string locationSubPath)
151 return OpenMachineConfiguration ();
154 [MonoLimitation("Mono does not support remote configuration")]
155 public static _Configuration OpenMachineConfiguration (string locationSubPath,
156 string server)
158 if (server == null)
159 return OpenMachineConfiguration (locationSubPath);
161 throw new NotSupportedException ("Mono doesn't support remote configuration");
164 [MonoLimitation("Mono does not support remote configuration")]
165 public static _Configuration OpenMachineConfiguration (string locationSubPath,
166 string server,
167 IntPtr userToken)
169 if (server == null)
170 return OpenMachineConfiguration (locationSubPath);
171 throw new NotSupportedException ("Mono doesn't support remote configuration");
174 [MonoLimitation("Mono does not support remote configuration")]
175 public static _Configuration OpenMachineConfiguration (string locationSubPath,
176 string server,
177 string userName,
178 string password)
180 if (server == null)
181 return OpenMachineConfiguration (locationSubPath);
182 throw new NotSupportedException ("Mono doesn't support remote configuration");
185 public static _Configuration OpenWebConfiguration (string path)
187 return OpenWebConfiguration (path, null, null, null, null, null);
190 public static _Configuration OpenWebConfiguration (string path, string site)
192 return OpenWebConfiguration (path, site, null, null, null, null);
195 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath)
197 return OpenWebConfiguration (path, site, locationSubPath, null, null, null);
200 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server)
202 return OpenWebConfiguration (path, site, locationSubPath, server, null, null);
205 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, IntPtr userToken)
207 return OpenWebConfiguration (path, site, locationSubPath, server, null, null);
210 public static _Configuration OpenWebConfiguration (string path, string site, string locationSubPath, string server, string userName, string password)
212 if (path == null || path.Length == 0)
213 path = "/";
215 _Configuration conf;
217 conf = (_Configuration) configurations [path];
218 if (conf == null) {
219 try {
220 conf = ConfigurationFactory.Create (typeof (WebConfigurationHost), null, path, site, locationSubPath, server, userName, password);
221 configurations [path] = conf;
222 } catch (Exception ex) {
223 lock (hasConfigErrorsLock) {
224 hasConfigErrors = true;
226 throw ex;
229 return conf;
232 public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path)
234 return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path);
237 public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path, string site)
239 return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path, site);
242 public static _Configuration OpenMappedWebConfiguration (WebConfigurationFileMap fileMap, string path, string site, string locationSubPath)
244 return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap, path, site, locationSubPath);
247 public static _Configuration OpenMappedMachineConfiguration (ConfigurationFileMap fileMap)
249 return ConfigurationFactory.Create (typeof(WebConfigurationHost), fileMap);
252 public static _Configuration OpenMappedMachineConfiguration (ConfigurationFileMap fileMap,
253 string locationSubPath)
255 return OpenMappedMachineConfiguration (fileMap);
258 internal static object SafeGetSection (string sectionName, Type configSectionType)
260 try {
261 return GetSection (sectionName);
262 } catch (Exception) {
263 if (configSectionType != null)
264 return Activator.CreateInstance (configSectionType);
265 return null;
269 internal static object SafeGetSection (string sectionName, string path, Type configSectionType)
271 try {
272 return GetSection (sectionName, path);
273 } catch (Exception) {
274 if (configSectionType != null)
275 return Activator.CreateInstance (configSectionType);
276 return null;
280 public static object GetSection (string sectionName)
282 return GetSection (sectionName, GetCurrentPath (HttpContext.Current));
285 public static object GetSection (string sectionName, string path)
287 object cachedSection = sectionCache [GetSectionCacheKey (sectionName, path)];
288 if (cachedSection != null)
289 return cachedSection;
291 _Configuration c = OpenWebConfiguration (path);
292 ConfigurationSection section = c.GetSection (sectionName);
294 if (section == null)
295 return null;
297 #if TARGET_J2EE
298 object value = get_runtime_object.Invoke (section, new object [0]);
299 if (String.CompareOrdinal ("appSettings", sectionName) == 0) {
300 NameValueCollection collection;
301 collection = new KeyValueMergedCollection (HttpContext.Current, (NameValueCollection) value);
302 value = collection;
305 AddSectionToCache (GetSectionCacheKey (sectionName, path), value);
306 return value;
307 #else
308 object value = SettingsMappingManager.MapSection (get_runtime_object.Invoke (section, new object [0]));
309 AddSectionToCache (GetSectionCacheKey (sectionName, path), value);
310 return value;
311 #endif
314 static string GetCurrentPath (HttpContext ctx)
316 return (ctx != null && ctx.Request != null) ? ctx.Request.Path : HttpRuntime.AppDomainAppVirtualPath;
319 internal static void RemoveConfigurationFromCache (HttpContext ctx)
321 configurations.Remove (GetCurrentPath (ctx));
324 readonly static MethodInfo get_runtime_object = typeof (ConfigurationSection).GetMethod ("GetRuntimeObject", BindingFlags.NonPublic | BindingFlags.Instance);
326 public static object GetWebApplicationSection (string sectionName)
328 string path = (HttpContext.Current == null
329 || HttpContext.Current.Request == null
330 || HttpContext.Current.Request.ApplicationPath == null
331 || HttpContext.Current.Request.ApplicationPath == "") ?
332 String.Empty : HttpContext.Current.Request.ApplicationPath;
334 return GetSection (sectionName, path);
337 public static NameValueCollection AppSettings {
338 get { return ConfigurationManager.AppSettings; }
341 public static ConnectionStringSettingsCollection ConnectionStrings {
342 get { return ConfigurationManager.ConnectionStrings; }
345 internal static IInternalConfigConfigurationFactory ConfigurationFactory {
346 get { return configFactory; }
349 static void AddSectionToCache (string key, object section)
351 if (sectionCache [key] != null)
352 return;
354 Hashtable tmpTable = (Hashtable) sectionCache.Clone ();
355 if (tmpTable.Contains (key))
356 return;
358 tmpTable.Add (key, section);
359 sectionCache = tmpTable;
362 static string GetSectionCacheKey (string sectionName, string path)
364 return string.Concat (path, "/", sectionName);
368 #region stuff copied from WebConfigurationSettings
369 #if TARGET_J2EE
370 static internal IConfigurationSystem oldConfig {
371 get {
372 return (IConfigurationSystem)AppDomain.CurrentDomain.GetData("WebConfigurationManager.oldConfig");
374 set {
375 AppDomain.CurrentDomain.SetData("WebConfigurationManager.oldConfig", value);
379 static private Web20DefaultConfig config {
380 get {
381 return (Web20DefaultConfig) AppDomain.CurrentDomain.GetData ("Web20DefaultConfig.config");
383 set {
384 AppDomain.CurrentDomain.SetData ("Web20DefaultConfig.config", value);
388 static private IInternalConfigSystem configSystem {
389 get {
390 return (IInternalConfigSystem) AppDomain.CurrentDomain.GetData ("IInternalConfigSystem.configSystem");
392 set {
393 AppDomain.CurrentDomain.SetData ("IInternalConfigSystem.configSystem", value);
396 #else
397 static internal IConfigurationSystem oldConfig;
398 static Web20DefaultConfig config;
399 //static IInternalConfigSystem configSystem;
400 #endif
401 const BindingFlags privStatic = BindingFlags.NonPublic | BindingFlags.Static;
402 static readonly object lockobj = new object ();
404 internal static void Init ()
406 lock (lockobj) {
407 if (config != null)
408 return;
410 /* deal with the ConfigurationSettings stuff */
412 Web20DefaultConfig settings = Web20DefaultConfig.GetInstance ();
413 Type t = typeof (ConfigurationSettings);
414 MethodInfo changeConfig = t.GetMethod ("ChangeConfigurationSystem",
415 privStatic);
417 if (changeConfig == null)
418 throw new ConfigurationException ("Cannot find method CCS");
420 object [] args = new object [] {settings};
421 oldConfig = (IConfigurationSystem)changeConfig.Invoke (null, args);
422 config = settings;
424 config.Init ();
427 /* deal with the ConfigurationManager stuff */
429 HttpConfigurationSystem system = new HttpConfigurationSystem ();
430 Type t = typeof (ConfigurationManager);
431 MethodInfo changeConfig = t.GetMethod ("ChangeConfigurationSystem",
432 privStatic);
434 if (changeConfig == null)
435 throw new ConfigurationException ("Cannot find method CCS");
437 object [] args = new object [] {system};
438 changeConfig.Invoke (null, args);
439 //configSystem = system;
445 class Web20DefaultConfig : IConfigurationSystem
447 #if TARGET_J2EE
448 static private Web20DefaultConfig instance {
449 get {
450 Web20DefaultConfig val = (Web20DefaultConfig)AppDomain.CurrentDomain.GetData("Web20DefaultConfig.instance");
451 if (val == null) {
452 val = new Web20DefaultConfig();
453 AppDomain.CurrentDomain.SetData("Web20DefaultConfig.instance", val);
455 return val;
457 set {
458 AppDomain.CurrentDomain.SetData("Web20DefaultConfig.instance", value);
461 #else
462 static Web20DefaultConfig instance;
463 #endif
465 static Web20DefaultConfig ()
467 instance = new Web20DefaultConfig ();
470 public static Web20DefaultConfig GetInstance ()
472 return instance;
475 public object GetConfig (string sectionName)
477 object o = WebConfigurationManager.GetWebApplicationSection (sectionName);
479 if (o == null || o is IgnoreSection) {
480 /* this can happen when the section
481 * handler doesn't subclass from
482 * ConfigurationSection. let's be
483 * nice and try to load it using the
484 * 1.x style routines in case there's
485 * a 1.x section handler registered
486 * for it.
488 object o1 = WebConfigurationManager.oldConfig.GetConfig (sectionName);
489 if (o1 != null)
490 return o1;
493 return o;
496 public void Init ()
498 // nothing. We need a context.
502 #endregion
505 #endif