| File: System\Configuration\SectionRecord.cs | Web Access |
| Project: src\runtime\src\libraries\System.Configuration.ConfigurationManager\src\System.Configuration.ConfigurationManager.csproj (System.Configuration.ConfigurationManager) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics; namespace System.Configuration { [DebuggerDisplay("SectionRecord {ConfigKey}")] internal sealed class SectionRecord { // // Runtime flags below 0x10000 // // locked by parent input, either because a parent section is locked, // a parent section locks all children, or a location input for this // configPath has allowOverride=false. private const int FlagLocked = 0x00000001; // lock children of this section private const int FlagLockChildren = 0x00000002; // propagation of FactoryRecord.RequirePermission private const int FlagRequirePermission = 0x00000008; // Look at AddLocationInput for explanation of this flag's purpose private const int FlagLocationInputLockApplied = 0x00000010; // Look at AddIndirectLocationInput for explanation of this flag's purpose private const int FlagIndirectLocationInputLockApplied = 0x00000020; // The flag gives us the inherited lock mode for this section record without the file input // We need this to support SectionInformation.OverrideModeEffective. private const int FlagChildrenLockWithoutFileInput = 0x00000040; // // Designtime flags at or above 0x00010000 // // the section has been added to the update list private const int FlagAddUpdate = 0x00010000; // result can be null, so we use this object to indicate whether it has been evaluated private static readonly object s_unevaluated = new object(); // config key // The input from this file private SafeBitVector32 _flags; // This special input is used only when creating a location config record. // The inputs are from location tags which are found in the same config file as the // location config configPath, but point to the parent paths of the location config // configPath. See the comment for VSWhidbey 540184 in Init() in // BaseConfigurationRecord.cs for more details. // The input from location sections // This list is ordered to keep oldest ancestors at the front // the cached result of evaluating this section // the cached result of evaluating this section after GetRuntimeObject is called internal SectionRecord(string configKey) { ConfigKey = configKey; Result = s_unevaluated; ResultRuntimeObject = s_unevaluated; } internal string ConfigKey { get; } internal bool Locked => _flags[FlagLocked]; internal bool LockChildren => _flags[FlagLockChildren]; internal bool LockChildrenWithoutFileInput { get { // Start assuming we dont have a file input // When we don't have file input the lock mode for children is the same for LockChildren and LockChildrenWithoutFileInput bool result = LockChildren; if (HasFileInput) result = _flags[FlagChildrenLockWithoutFileInput]; return result; } } internal bool RequirePermission { get { return _flags[FlagRequirePermission]; } set { _flags[FlagRequirePermission] = value; } } internal bool AddUpdate { get { return _flags[FlagAddUpdate]; } set { _flags[FlagAddUpdate] = value; } } internal bool HasLocationInputs => (LocationInputs != null) && (LocationInputs.Count > 0); internal List<SectionInput> LocationInputs { get; private set; } internal SectionInput LastLocationInput => HasLocationInputs ? LocationInputs[LocationInputs.Count - 1] : null; internal bool HasFileInput => FileInput != null; internal SectionInput FileInput { get; private set; } internal bool HasIndirectLocationInputs => (IndirectLocationInputs != null) && (IndirectLocationInputs.Count > 0); internal List<SectionInput> IndirectLocationInputs { get; private set; } internal SectionInput LastIndirectLocationInput => HasIndirectLocationInputs ? IndirectLocationInputs[IndirectLocationInputs.Count - 1] : null; internal bool HasInput => HasLocationInputs || HasFileInput || HasIndirectLocationInputs; internal bool HasResult => Result != s_unevaluated; internal bool HasResultRuntimeObject => ResultRuntimeObject != s_unevaluated; internal object Result { get; set; } internal object ResultRuntimeObject { get; set; } internal bool HasErrors { get { if (HasLocationInputs) foreach (SectionInput input in LocationInputs) if (input.HasErrors) return true; if (HasIndirectLocationInputs) foreach (SectionInput input in IndirectLocationInputs) if (input.HasErrors) return true; return HasFileInput && FileInput.HasErrors; } } internal void AddLocationInput(SectionInput sectionInput) { AddLocationInputImpl(sectionInput, false); } internal void ChangeLockSettings(OverrideMode forSelf, OverrideMode forChildren) { if (forSelf != OverrideMode.Inherit) { _flags[FlagLocked] = forSelf == OverrideMode.Deny; _flags[FlagLockChildren] = forSelf == OverrideMode.Deny; } if (forChildren != OverrideMode.Inherit) _flags[FlagLockChildren] = (forSelf == OverrideMode.Deny) || (forChildren == OverrideMode.Deny); } // AddFileInput internal void AddFileInput(SectionInput sectionInput) { Debug.Assert(sectionInput != null); FileInput = sectionInput; // If the file input has an explicit value for its children locking - use it // Note we dont change the current lock setting if (!sectionInput.HasErrors && (sectionInput.SectionXmlInfo.OverrideModeSetting.OverrideMode != OverrideMode.Inherit)) { // Store the current setting before applying the lock from the file input // So that if the user changes the current OverrideMode on this configKey to "Inherit" // we will know what we are going to inherit ( used in SectionInformation.OverrideModeEffective ) // Note that we cannot use BaseConfigurationRecord.ResolveOverrideModeFromParent as it gives us only the lock // resolved up to our immediate parent which does not inlcude normal and indirect location imputs _flags[FlagChildrenLockWithoutFileInput] = LockChildren; ChangeLockSettings(OverrideMode.Inherit, sectionInput.SectionXmlInfo.OverrideModeSetting.OverrideMode); } } internal void RemoveFileInput() { if (FileInput != null) { FileInput = null; // Reset LockChildren flag to the value provided by // location input or inherited sections. _flags[FlagLockChildren] = Locked; } } internal void AddIndirectLocationInput(SectionInput sectionInput) { AddLocationInputImpl(sectionInput, true); } private void AddLocationInputImpl(SectionInput sectionInput, bool isIndirectLocation) { List<SectionInput> inputs = isIndirectLocation ? IndirectLocationInputs : LocationInputs; int flag = isIndirectLocation ? FlagIndirectLocationInputLockApplied : FlagLocationInputLockApplied; if (inputs == null) { inputs = new List<SectionInput>(1); if (isIndirectLocation) IndirectLocationInputs = inputs; else LocationInputs = inputs; } // The list of locationSections is traversed from child to parent, // so insert at the beginning of the list. inputs.Insert(0, sectionInput); // Only the overrideMode from the parent thats closest to the SectionRecord has effect // // For location input: // Remember that this method will be called for location inputs coming from the immediate parent first // and then walking the hierarchy up to the root level // // For indirect location input: // This method will be first called for indirect input closest to the location config if (!sectionInput.HasErrors && !_flags[flag]) { OverrideMode modeLocation = sectionInput.SectionXmlInfo.OverrideModeSetting.OverrideMode; if (modeLocation != OverrideMode.Inherit) { ChangeLockSettings(modeLocation, modeLocation); _flags[flag] = true; } } } internal void ClearRawXml() { if (HasLocationInputs) foreach (SectionInput locationInput in LocationInputs) locationInput.SectionXmlInfo.RawXml = null; if (HasIndirectLocationInputs) { foreach (SectionInput indirectLocationInput in IndirectLocationInputs) indirectLocationInput.SectionXmlInfo.RawXml = null; } if (HasFileInput) FileInput.SectionXmlInfo.RawXml = null; } internal void ClearResult() { FileInput?.ClearResult(); if (LocationInputs != null) foreach (SectionInput input in LocationInputs) input.ClearResult(); Result = s_unevaluated; ResultRuntimeObject = s_unevaluated; } private List<ConfigurationException> GetAllErrors() { List<ConfigurationException> allErrors = null; if (HasLocationInputs) foreach (SectionInput input in LocationInputs) ErrorsHelper.AddErrors(ref allErrors, input.Errors); if (HasIndirectLocationInputs) { foreach (SectionInput input in IndirectLocationInputs) ErrorsHelper.AddErrors(ref allErrors, input.Errors); } if (HasFileInput) ErrorsHelper.AddErrors(ref allErrors, FileInput.Errors); return allErrors; } internal void ThrowOnErrors() { if (HasErrors) throw new ConfigurationErrorsException(GetAllErrors()); } } }