InternalConfigRoot
using System.Threading;
namespace System.Configuration.Internal
{
internal sealed class InternalConfigRoot : IInternalConfigRoot
{
private ReaderWriterLock _hierarchyLock;
private bool _isDesignTime;
internal IInternalConfigHost Host { get; set; }
internal UpdateConfigHost UpdateConfigHost { get; set; }
internal BaseConfigurationRecord RootConfigRecord { get; set; }
internal Configuration CurrentConfiguration { get; }
bool IInternalConfigRoot.IsDesignTime {
get {
return _isDesignTime;
}
}
public event InternalConfigEventHandler ConfigChanged;
public event InternalConfigEventHandler ConfigRemoved;
internal InternalConfigRoot()
{
}
internal InternalConfigRoot(Configuration currentConfiguration, UpdateConfigHost host)
{
CurrentConfiguration = currentConfiguration;
UpdateConfigHost = host;
}
void IInternalConfigRoot.Init(IInternalConfigHost host, bool isDesignTime)
{
Host = host;
_isDesignTime = isDesignTime;
_hierarchyLock = new ReaderWriterLock();
if (_isDesignTime)
RootConfigRecord = MgmtConfigurationRecord.Create(this, null, string.Empty, null);
else
RootConfigRecord = (BaseConfigurationRecord)RuntimeConfigurationRecord.Create(this, null, string.Empty);
}
public object GetSection(string section, string configPath)
{
return ((BaseConfigurationRecord)GetUniqueConfigRecord(configPath)).GetSection(section);
}
public string GetUniqueConfigPath(string configPath)
{
return GetUniqueConfigRecord(configPath)?.ConfigPath;
}
public IInternalConfigRecord GetUniqueConfigRecord(string configPath)
{
BaseConfigurationRecord baseConfigurationRecord = (BaseConfigurationRecord)GetConfigRecord(configPath);
while (baseConfigurationRecord.IsEmpty) {
BaseConfigurationRecord parent = baseConfigurationRecord.Parent;
if (parent.IsRootConfig)
break;
baseConfigurationRecord = parent;
}
return baseConfigurationRecord;
}
public IInternalConfigRecord GetConfigRecord(string configPath)
{
if (ConfigPathUtility.IsValid(configPath)) {
string[] parts = ConfigPathUtility.GetParts(configPath);
try {
AcquireHierarchyLockForRead();
HlFindConfigRecord(parts, out int nextIndex, out BaseConfigurationRecord currentRecord);
if (nextIndex == parts.Length || !currentRecord.HlNeedsChildFor(parts[nextIndex]))
return currentRecord;
} finally {
ReleaseHierarchyLockForRead();
}
try {
AcquireHierarchyLockForWrite();
HlFindConfigRecord(parts, out int nextIndex2, out BaseConfigurationRecord currentRecord2);
if (nextIndex2 != parts.Length) {
string text = string.Join("/", parts, 0, nextIndex2);
while (nextIndex2 < parts.Length && currentRecord2.HlNeedsChildFor(parts[nextIndex2])) {
string text2 = parts[nextIndex2];
text = ConfigPathUtility.Combine(text, text2);
BaseConfigurationRecord baseConfigurationRecord = _isDesignTime ? MgmtConfigurationRecord.Create(this, currentRecord2, text, null) : ((BaseConfigurationRecord)RuntimeConfigurationRecord.Create(this, currentRecord2, text));
currentRecord2.HlAddChild(text2, baseConfigurationRecord);
nextIndex2++;
currentRecord2 = baseConfigurationRecord;
}
return currentRecord2;
}
return currentRecord2;
} finally {
ReleaseHierarchyLockForWrite();
}
}
throw ExceptionUtil.ParameterInvalid("configPath");
}
public void RemoveConfig(string configPath)
{
RemoveConfigImpl(configPath, null);
}
private void AcquireHierarchyLockForRead()
{
if (_hierarchyLock.IsReaderLockHeld)
throw ExceptionUtil.UnexpectedError("System.Configuration.Internal.InternalConfigRoot::AcquireHierarchyLockForRead - reader lock already held by this thread");
if (_hierarchyLock.IsWriterLockHeld)
throw ExceptionUtil.UnexpectedError("System.Configuration.Internal.InternalConfigRoot::AcquireHierarchyLockForRead - writer lock already held by this thread");
_hierarchyLock.AcquireReaderLock(-1);
}
private void ReleaseHierarchyLockForRead()
{
if (_hierarchyLock.IsReaderLockHeld)
_hierarchyLock.ReleaseReaderLock();
}
private void AcquireHierarchyLockForWrite()
{
if (_hierarchyLock.IsReaderLockHeld)
throw ExceptionUtil.UnexpectedError("System.Configuration.Internal.InternalConfigRoot::AcquireHierarchyLockForWrite - reader lock already held by this thread");
if (_hierarchyLock.IsWriterLockHeld)
throw ExceptionUtil.UnexpectedError("System.Configuration.Internal.InternalConfigRoot::AcquireHierarchyLockForWrite - writer lock already held by this thread");
_hierarchyLock.AcquireWriterLock(-1);
}
private void ReleaseHierarchyLockForWrite()
{
if (_hierarchyLock.IsWriterLockHeld)
_hierarchyLock.ReleaseWriterLock();
}
private void HlFindConfigRecord(string[] parts, out int nextIndex, out BaseConfigurationRecord currentRecord)
{
currentRecord = RootConfigRecord;
for (nextIndex = 0; nextIndex < parts.Length; nextIndex++) {
BaseConfigurationRecord baseConfigurationRecord = currentRecord.HlGetChild(parts[nextIndex]);
if (baseConfigurationRecord == null)
break;
currentRecord = baseConfigurationRecord;
}
}
private void RemoveConfigImpl(string configPath, BaseConfigurationRecord configRecord)
{
if (!ConfigPathUtility.IsValid(configPath))
throw ExceptionUtil.ParameterInvalid("configPath");
string[] parts = ConfigPathUtility.GetParts(configPath);
BaseConfigurationRecord currentRecord;
try {
AcquireHierarchyLockForWrite();
HlFindConfigRecord(parts, out int nextIndex, out currentRecord);
if (nextIndex != parts.Length || (configRecord != null && configRecord != currentRecord))
return;
currentRecord.Parent.HlRemoveChild(parts[parts.Length - 1]);
} finally {
ReleaseHierarchyLockForWrite();
}
OnConfigRemoved(new InternalConfigEventArgs(configPath));
currentRecord.CloseRecursive();
}
public void RemoveConfigRecord(BaseConfigurationRecord configRecord)
{
RemoveConfigImpl(configRecord.ConfigPath, configRecord);
}
public void ClearResult(BaseConfigurationRecord configRecord, string configKey, bool forceEvaluation)
{
string[] parts = ConfigPathUtility.GetParts(configRecord.ConfigPath);
try {
AcquireHierarchyLockForRead();
HlFindConfigRecord(parts, out int nextIndex, out BaseConfigurationRecord currentRecord);
if (nextIndex == parts.Length && configRecord == currentRecord)
currentRecord.HlClearResultRecursive(configKey, forceEvaluation);
} finally {
ReleaseHierarchyLockForRead();
}
}
private void OnConfigRemoved(InternalConfigEventArgs e)
{
this.ConfigRemoved?.Invoke(this, e);
}
internal void FireConfigChanged(string configPath)
{
OnConfigChanged(new InternalConfigEventArgs(configPath));
}
private void OnConfigChanged(InternalConfigEventArgs e)
{
this.ConfigChanged?.Invoke(this, e);
}
}
}