The Labs \ Source Viewer \ SSCLI \ System.Configuration \ ClientConfigurationSystem

  1. //------------------------------------------------------------------------------
  2. // <copyright file="ClientConfigurationSystem.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Configuration
  16. {
  17.     using System.Configuration.Internal;
  18.     using System.Globalization;
  19.     using System.Collections;
  20.     using System.IO;
  21.     using System.Xml;
  22.     using System.Security;
  23.     using System.Security.Permissions;
  24.     using System.Threading;
  25.     using System.Net;
  26.     using Assembly = System.Reflection.Assembly;
  27.     using StringBuilder = System.Text.StringBuilder;
  28.    
  29.     internal sealed class ClientConfigurationSystem : IInternalConfigSystem
  30.     {
  31.         private const string SystemDiagnosticsConfigKey = "system.diagnostics";
  32.         private const string SystemNetGroupKey = "system.net/";
  33.        
  34.         private IConfigSystem _configSystem;
  35.         private IInternalConfigRoot _configRoot;
  36.         private ClientConfigurationHost _configHost;
  37.         private IInternalConfigRecord _machineConfigRecord;
  38.         private IInternalConfigRecord _completeConfigRecord;
  39.         private Exception _initError;
  40.         private bool _isInitInProgress;
  41.         private bool _isMachineConfigInited;
  42.         private bool _isUserConfigInited;
  43.         private bool _isAppConfigHttp;
  44.        
  45.        
  46.         internal ClientConfigurationSystem()
  47.         {
  48.             _configSystem = new ConfigSystem();
  49.             _configSystem.Init(typeof(ClientConfigurationHost), null, null);
  50.            
  51.             _configHost = (ClientConfigurationHost)_configSystem.Host;
  52.             _configRoot = _configSystem.Root;
  53.            
  54.             _configRoot.ConfigRemoved += OnConfigRemoved;
  55.            
  56.             _isAppConfigHttp = _configHost.IsAppConfigHttp;
  57.         }
  58.        
  59.         // Return true if the section might be used during initialization of the configuration system,
  60.         // and thus lead to deadlock if appropriate measures are not taken.
  61.         bool IsSectionUsedInInit(string configKey)
  62.         {
  63.             return configKey == SystemDiagnosticsConfigKey || (_isAppConfigHttp && configKey.StartsWith(SystemNetGroupKey, StringComparison.Ordinal));
  64.         }
  65.        
  66.         // Return true if the section should only use the machine configuration and not use the
  67.         // application configuration. This is only true for system.net sections when the configuration
  68.         // file for the application is downloaded via http using System.Net.WebClient.
  69.         bool DoesSectionOnlyUseMachineConfig(string configKey)
  70.         {
  71.             return _isAppConfigHttp && configKey.StartsWith(SystemNetGroupKey, StringComparison.Ordinal);
  72.         }
  73.        
  74.         // Ensure that initialization has completed, while handling re-entrancy issues
  75.         // for certain sections that may be used during initialization itself.
  76.         void EnsureInit(string configKey)
  77.         {
  78.             bool doInit = false;
  79.            
  80.             lock (this) {
  81.                 // If the user config is not initialized, then we must either:
  82.                 // a. Perform the initialization ourselves if no other thread is doing it, or
  83.                 // b. Wait for the initialization to complete if we know the section is not used during initialization itself, or
  84.                 // c. Ignore initialization if the section can be used during initialization. Note that GetSection()
  85.                 // returns null is initialization has not completed.
  86.                 if (!_isUserConfigInited) {
  87.                     if (!_isInitInProgress) {
  88.                         _isInitInProgress = true;
  89.                         doInit = true;
  90.                     }
  91.                     else if (!IsSectionUsedInInit(configKey)) {
  92.                         // Wait for initialization to complete.
  93.                         Monitor.Wait(this);
  94.                     }
  95.                 }
  96.             }
  97.            
  98.             if (doInit) {
  99.                 try {
  100.                     try {
  101.                         try {
  102.                             // Initialize machine configuration.
  103.                             _machineConfigRecord = _configRoot.GetConfigRecord(ClientConfigurationHost.MachineConfigPath);
  104.                            
  105.                             _machineConfigRecord.ThrowIfInitErrors();
  106.                            
  107.                             // Make machine configuration available to system.net sections
  108.                             // when application configuration is downloaded via http.
  109.                             _isMachineConfigInited = true;
  110.                            
  111.                             //
  112.                             // Prevent deadlocks in the networking classes by loading
  113.                             // networking config before making a networking request.
  114.                             // Any requests for sections used in initialization during
  115.                             // the call to EnsureConfigLoaded() will be served by
  116.                             // _machine.config or will return null.
  117.                             //
  118.                             if (_isAppConfigHttp) {
  119.                                 ConfigurationManagerHelperFactory.Instance.EnsureNetConfigLoaded();
  120.                             }
  121.                            
  122.                             //
  123.                             // Now load the rest of configuration
  124.                             //
  125.                             _configHost.RefreshConfigPaths();
  126.                             string configPath;
  127.                             if (_configHost.HasLocalConfig) {
  128.                                 configPath = ClientConfigurationHost.LocalUserConfigPath;
  129.                             }
  130.                             else if (_configHost.HasRoamingConfig) {
  131.                                 configPath = ClientConfigurationHost.RoamingUserConfigPath;
  132.                             }
  133.                             else {
  134.                                 configPath = ClientConfigurationHost.ExeConfigPath;
  135.                             }
  136.                            
  137.                             _completeConfigRecord = _configRoot.GetConfigRecord(configPath);
  138.                             _completeConfigRecord.ThrowIfInitErrors();
  139.                            
  140.                             _isUserConfigInited = true;
  141.                         }
  142.                         catch (Exception e) {
  143.                             _initError = new ConfigurationErrorsException(SR.GetString(SR.Config_client_config_init_error), e);
  144.                             throw _initError;
  145.                         }
  146.                         catch {
  147.                             _initError = new ConfigurationErrorsException(SR.GetString(SR.Config_client_config_init_error));
  148.                             throw _initError;
  149.                         }
  150.                     }
  151.                     catch {
  152.                         ConfigurationManager.SetInitError(_initError);
  153.                         _isMachineConfigInited = true;
  154.                         _isUserConfigInited = true;
  155.                         throw;
  156.                     }
  157.                 }
  158.                 finally {
  159.                     lock (this) {
  160.                         try {
  161.                             // Notify ConfigurationSettings that initialization has fully completed,
  162.                             // even if unsuccessful.
  163.                             ConfigurationManager.CompleteConfigInit();
  164.                            
  165.                             _isInitInProgress = false;
  166.                            
  167.                         }
  168.                         finally {
  169.                             // Wake up all threads waiting for initialization to complete.
  170.                             Monitor.PulseAll(this);
  171.                         }
  172.                     }
  173.                 }
  174.             }
  175.         }
  176.        
  177.         private void PrepareClientConfigSystem(string sectionName)
  178.         {
  179.             // Ensure the configuration system is inited for this section.
  180.             if (!_isUserConfigInited) {
  181.                 EnsureInit(sectionName);
  182.             }
  183.            
  184.             // If an error occurred during initialzation, throw it.
  185.             if (_initError != null) {
  186.                 throw _initError;
  187.             }
  188.         }
  189.        
  190.         //
  191.         // If config has been removed because initialization was not complete,
  192.         // fetch a new configuration record. The record will be created and
  193.         // completely initialized as RequireCompleteInit() will have been called
  194.         // on the ClientConfigurationHost before we receive this event.
  195.         //
  196.         private void OnConfigRemoved(object sender, InternalConfigEventArgs e)
  197.         {
  198.             try {
  199.                 IInternalConfigRecord newConfigRecord = _configRoot.GetConfigRecord(_completeConfigRecord.ConfigPath);
  200.                 _completeConfigRecord = newConfigRecord;
  201.                 _completeConfigRecord.ThrowIfInitErrors();
  202.             }
  203.             catch (Exception ex) {
  204.                 _initError = new ConfigurationErrorsException(SR.GetString(SR.Config_client_config_init_error), ex);
  205.                 ConfigurationManager.SetInitError(_initError);
  206.                 throw _initError;
  207.             }
  208.             catch {
  209.                 _initError = new ConfigurationErrorsException(SR.GetString(SR.Config_client_config_init_error));
  210.                 ConfigurationManager.SetInitError(_initError);
  211.                 throw _initError;
  212.             }
  213.         }
  214.        
  215.         object IInternalConfigSystem.GetSection(string sectionName)
  216.         {
  217.             PrepareClientConfigSystem(sectionName);
  218.            
  219.             // Get the appropriate config record for the section.
  220.             IInternalConfigRecord configRecord = null;
  221.             if (DoesSectionOnlyUseMachineConfig(sectionName)) {
  222.                 if (_isMachineConfigInited) {
  223.                     configRecord = _machineConfigRecord;
  224.                 }
  225.             }
  226.             else {
  227.                 if (_isUserConfigInited) {
  228.                     configRecord = _completeConfigRecord;
  229.                 }
  230.             }
  231.            
  232.             // Call GetSection(), or return null if no configuration is yet available.
  233.             if (configRecord != null) {
  234.                 return configRecord.GetSection(sectionName);
  235.             }
  236.             else {
  237.                 return null;
  238.             }
  239.         }
  240.        
  241.         void IInternalConfigSystem.RefreshConfig(string sectionName)
  242.         {
  243.             PrepareClientConfigSystem(sectionName);
  244.            
  245.             if (_isMachineConfigInited) {
  246.                 _machineConfigRecord.RefreshSection(sectionName);
  247.             }
  248.         }
  249.        
  250.         // Supports user config
  251.         bool IInternalConfigSystem.SupportsUserConfig {
  252.             get { return true; }
  253.         }
  254.     }
  255. }

Developer Fusion