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