423 lines
15 KiB
C#
423 lines
15 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="SectionRecord.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
namespace System.Configuration {
|
|
using System.Configuration.Internal;
|
|
using System.Collections;
|
|
using System.Collections.Specialized;
|
|
using System.Collections.Generic;
|
|
using System.Configuration;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Reflection;
|
|
using System.Xml;
|
|
|
|
[System.Diagnostics.DebuggerDisplay("SectionRecord {ConfigKey}")]
|
|
internal class SectionRecord {
|
|
//
|
|
// Flags constants
|
|
//
|
|
|
|
//
|
|
// 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 Flag_Locked = 0x00000001;
|
|
|
|
// lock children of this section
|
|
private const int Flag_LockChildren = 0x00000002;
|
|
|
|
// propagation of FactoryRecord.IsFactoryTrustedWithoutAptca
|
|
private const int Flag_IsResultTrustedWithoutAptca = 0x00000004;
|
|
|
|
// propagation of FactoryRecord.RequirePermission
|
|
private const int Flag_RequirePermission = 0x00000008;
|
|
|
|
// Look at AddLocationInput for explanation of this flag's purpose
|
|
private const int Flag_LocationInputLockApplied = 0x00000010;
|
|
|
|
// Look at AddIndirectLocationInput for explanation of this flag's purpose
|
|
private const int Flag_IndirectLocationInputLockApplied = 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 Flag_ChildrenLockWithoutFileInput = 0x00000040;
|
|
|
|
//
|
|
// Designtime flags at or above 0x00010000
|
|
//
|
|
|
|
// the section has been added to the update list
|
|
private const int Flag_AddUpdate = 0x00010000;
|
|
|
|
// result can be null, so we use this object to indicate whether it has been evaluated
|
|
static object s_unevaluated = new object();
|
|
|
|
private SafeBitVector32 _flags;
|
|
|
|
// config key
|
|
private string _configKey;
|
|
|
|
// The input from location sections
|
|
// This list is ordered to keep oldest ancestors at the front
|
|
private List<SectionInput> _locationInputs;
|
|
|
|
// The input from this file
|
|
private SectionInput _fileInput;
|
|
|
|
// 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.
|
|
private List<SectionInput> _indirectLocationInputs;
|
|
|
|
// the cached result of evaluating this section
|
|
private object _result;
|
|
|
|
// the cached result of evaluating this section after GetRuntimeObject is called
|
|
private object _resultRuntimeObject;
|
|
|
|
|
|
internal SectionRecord(string configKey) {
|
|
_configKey = configKey;
|
|
_result = s_unevaluated;
|
|
_resultRuntimeObject = s_unevaluated;
|
|
}
|
|
|
|
internal string ConfigKey {
|
|
get {return _configKey;}
|
|
}
|
|
|
|
internal bool Locked {
|
|
get {return _flags[Flag_Locked];}
|
|
}
|
|
|
|
internal bool LockChildren {
|
|
get {return _flags[Flag_LockChildren];}
|
|
}
|
|
|
|
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[Flag_ChildrenLockWithoutFileInput];
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
internal bool IsResultTrustedWithoutAptca {
|
|
get {return _flags[Flag_IsResultTrustedWithoutAptca];}
|
|
set {_flags[Flag_IsResultTrustedWithoutAptca] = value;}
|
|
}
|
|
|
|
internal bool RequirePermission {
|
|
get {return _flags[Flag_RequirePermission];}
|
|
set {_flags[Flag_RequirePermission] = value;}
|
|
}
|
|
|
|
internal bool AddUpdate {
|
|
get {return _flags[Flag_AddUpdate];}
|
|
set {_flags[Flag_AddUpdate] = value;}
|
|
}
|
|
|
|
internal bool HasLocationInputs {
|
|
get {
|
|
return _locationInputs != null && _locationInputs.Count > 0;
|
|
}
|
|
}
|
|
|
|
internal List<SectionInput> LocationInputs {
|
|
get {return _locationInputs;}
|
|
}
|
|
|
|
internal SectionInput LastLocationInput {
|
|
get {
|
|
if (HasLocationInputs) {
|
|
return _locationInputs[_locationInputs.Count - 1];
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void
|
|
AddLocationInput(SectionInput sectionInput) {
|
|
AddLocationInputImpl(sectionInput, false);
|
|
}
|
|
|
|
internal bool HasFileInput {
|
|
get {
|
|
return _fileInput != null;
|
|
}
|
|
}
|
|
|
|
internal SectionInput FileInput {
|
|
get { return _fileInput; }
|
|
}
|
|
|
|
internal void ChangeLockSettings(OverrideMode forSelf, OverrideMode forChildren) {
|
|
|
|
if (forSelf != OverrideMode.Inherit) {
|
|
_flags[Flag_Locked] = (forSelf == OverrideMode.Deny);
|
|
_flags[Flag_LockChildren] = (forSelf == OverrideMode.Deny);
|
|
}
|
|
|
|
if (forChildren != OverrideMode.Inherit) {
|
|
_flags[Flag_LockChildren] = ((forSelf == OverrideMode.Deny) || (forChildren == OverrideMode.Deny));
|
|
}
|
|
}
|
|
|
|
// AddFileInput
|
|
internal void AddFileInput(SectionInput sectionInput) {
|
|
Debug.Assert(sectionInput != null);
|
|
|
|
_fileInput = sectionInput;
|
|
|
|
if (!sectionInput.HasErrors) {
|
|
|
|
// If the file input has an explciti value for its children locking - use it
|
|
// Note we dont change the current lock setting
|
|
if (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[Flag_ChildrenLockWithoutFileInput] = 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[Flag_LockChildren] = Locked;
|
|
}
|
|
}
|
|
|
|
internal bool HasIndirectLocationInputs {
|
|
get {
|
|
return _indirectLocationInputs != null && _indirectLocationInputs.Count > 0;
|
|
}
|
|
}
|
|
|
|
internal List<SectionInput> IndirectLocationInputs {
|
|
get {return _indirectLocationInputs;}
|
|
}
|
|
|
|
internal SectionInput LastIndirectLocationInput {
|
|
get {
|
|
if (HasIndirectLocationInputs) {
|
|
return _indirectLocationInputs[_indirectLocationInputs.Count - 1];
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void
|
|
AddIndirectLocationInput(SectionInput sectionInput) {
|
|
AddLocationInputImpl(sectionInput, true);
|
|
}
|
|
|
|
private void
|
|
AddLocationInputImpl(SectionInput sectionInput, bool isIndirectLocation) {
|
|
List<SectionInput> inputs = isIndirectLocation ?
|
|
_indirectLocationInputs :
|
|
_locationInputs;
|
|
|
|
int flag = isIndirectLocation ?
|
|
Flag_IndirectLocationInputLockApplied :
|
|
Flag_LocationInputLockApplied;
|
|
|
|
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 comming 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) {
|
|
|
|
if (!_flags[flag]) {
|
|
OverrideMode modeLocation = sectionInput.SectionXmlInfo.OverrideModeSetting.OverrideMode;
|
|
|
|
if (modeLocation != OverrideMode.Inherit) {
|
|
ChangeLockSettings(modeLocation, modeLocation);
|
|
_flags[flag] = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal bool HasInput {
|
|
get {
|
|
return HasLocationInputs || HasFileInput || HasIndirectLocationInputs;
|
|
}
|
|
}
|
|
|
|
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 bool HasResult {
|
|
get {return _result != s_unevaluated;}
|
|
}
|
|
|
|
internal bool HasResultRuntimeObject {
|
|
get {return _resultRuntimeObject != s_unevaluated;}
|
|
}
|
|
|
|
internal object Result {
|
|
get {
|
|
// Useful assert, but it fires in the debugger when using automatic property evaluation
|
|
// Debug.Assert(_result != s_unevaluated, "_result != s_unevaluated");
|
|
|
|
return _result;
|
|
}
|
|
|
|
set {_result = value;}
|
|
}
|
|
|
|
internal object ResultRuntimeObject {
|
|
get {
|
|
// Useful assert, but it fires in the debugger when using automatic property evaluation
|
|
// Debug.Assert(_resultRuntimeObject != s_unevaluated, "_resultRuntimeObject != s_unevaluated");
|
|
|
|
return _resultRuntimeObject;
|
|
}
|
|
|
|
set {
|
|
_resultRuntimeObject = value;
|
|
}
|
|
}
|
|
|
|
internal void ClearResult() {
|
|
if (_fileInput != null) {
|
|
_fileInput.ClearResult();
|
|
}
|
|
|
|
if (_locationInputs != null) {
|
|
foreach (SectionInput input in _locationInputs) {
|
|
input.ClearResult();
|
|
}
|
|
}
|
|
|
|
_result = s_unevaluated;
|
|
_resultRuntimeObject = s_unevaluated;
|
|
}
|
|
|
|
//
|
|
// Error handling.
|
|
//
|
|
|
|
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 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (HasFileInput) {
|
|
if (FileInput.HasErrors) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
internal void ThrowOnErrors() {
|
|
if (HasErrors) {
|
|
throw new ConfigurationErrorsException(GetAllErrors());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|