|
//------------------------------------------------------------------------------
// <copyright file="ConfigurationElement.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using System;
using System.Configuration.Internal;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Security.Permissions;
using System.Xml;
using System.Globalization;
using System.ComponentModel;
using System.Security;
using System.Text;
namespace System.Configuration {
//
// Methods that are called by the configuration system, and must be overridable
// by derived classes that wish to implement their own serialization/deserialization
// IsModified()
// ResetModified()
// Reset(ConfigurationElement parentSection, object context)
// DeserializeSection(object context, XmlNode xmlNode)
// SerializeSection(ConfigurationElement parentSection, object context, string name)
//
public abstract class ConfigurationElement {
private const string LockAttributesKey = "lockAttributes";
private const string LockAllAttributesExceptKey = "lockAllAttributesExcept";
private const string LockElementsKey = "lockElements";
private const string LockAll = "*";
private const string LockAllElementsExceptKey = "lockAllElementsExcept";
private const string LockItemKey = "lockItem";
internal const string DefaultCollectionPropertyName = "";
private static string[] s_lockAttributeNames = new string[] {
LockAttributesKey,
LockAllAttributesExceptKey,
LockElementsKey,
LockAllElementsExceptKey,
LockItemKey,
};
private static Hashtable s_propertyBags = new Hashtable();
private static volatile Dictionary<Type,ConfigurationValidatorBase> s_perTypeValidators;
internal static readonly Object s_nullPropertyValue = new Object();
private static ConfigurationElementProperty s_ElementProperty =
new ConfigurationElementProperty(new DefaultValidator());
private bool _bDataToWrite;
private bool _bModified;
private bool _bReadOnly;
private bool _bElementPresent; // Set to false if any part of the element is not inherited
private bool _bInited;
internal ConfigurationLockCollection _lockedAttributesList;
internal ConfigurationLockCollection _lockedAllExceptAttributesList;
internal ConfigurationLockCollection _lockedElementsList;
internal ConfigurationLockCollection _lockedAllExceptElementsList;
private readonly ConfigurationValues _values;
private string _elementTagName;
private volatile ElementInformation _evaluationElement;
private ConfigurationElementProperty _elementProperty = s_ElementProperty;
internal ConfigurationValueFlags _fItemLocked;
internal ContextInformation _evalContext;
internal BaseConfigurationRecord _configRecord;
internal bool DataToWriteInternal {
get {
return _bDataToWrite;
}
set {
_bDataToWrite = value;
}
}
internal ConfigurationElement CreateElement(Type type) {
// We use this.GetType() as the calling type since all code paths which lead to
// CreateElement are protected methods, so inputs are provided by somebody in
// the current type hierarchy. Since we expect that the most subclassed type
// will be the most restricted security-wise, we'll use it as the calling type.
ConfigurationElement element = (ConfigurationElement)TypeUtil.CreateInstanceRestricted(callingType: GetType(), targetType: type);
element.CallInit();
return element;
}
protected ConfigurationElement() {
_values = new ConfigurationValues();
// Set the per-type validator ( this will actually have an effect only for an attributed model elements )
// Note that in the case where the property bag fot this.GetType() has not yet been created
// the validator for this instance will get applied in ApplyValidatorsRecursive ( see this.get_Properties )
ApplyValidator(this);
}
// Give elements that are added to a collection an opportunity to
//
protected internal virtual void Init() {
// If Init is called by the derived class, we may be able
// to set _bInited to true if the derived class properly
// calls Init on its base.
_bInited = true;
}
internal void CallInit() {
// Ensure Init is called just once
if (!_bInited) {
Init();
_bInited = true;
}
}
internal bool ElementPresent {
get {
return _bElementPresent;
}
set {
_bElementPresent = value;
}
}
internal string ElementTagName {
get {
return _elementTagName;
}
}
internal ConfigurationLockCollection LockedAttributesList {
get {
return _lockedAttributesList;
}
}
internal ConfigurationLockCollection LockedAllExceptAttributesList {
get {
return _lockedAllExceptAttributesList;
}
}
internal ConfigurationValueFlags ItemLocked {
get {
return _fItemLocked;
}
}
public ConfigurationLockCollection LockAttributes {
get {
if (_lockedAttributesList == null) {
_lockedAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedAttributes);
}
return _lockedAttributesList;
}
}
internal void MergeLocks(ConfigurationElement source) {
if (source != null) {
_fItemLocked = ((source._fItemLocked & ConfigurationValueFlags.Locked) != 0) ?
(ConfigurationValueFlags.Inherited | source._fItemLocked) : _fItemLocked;
if (source._lockedAttributesList != null) {
if (_lockedAttributesList == null) {
_lockedAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedAttributes);
}
foreach (string key in source._lockedAttributesList)
_lockedAttributesList.Add(key, ConfigurationValueFlags.Inherited); // Mark entry as from the parent - read only
}
if (source._lockedAllExceptAttributesList != null) {
if (_lockedAllExceptAttributesList == null) {
_lockedAllExceptAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedExceptionList, String.Empty, source._lockedAllExceptAttributesList);
}
StringCollection intersectionCollection = IntersectLockCollections(_lockedAllExceptAttributesList, source._lockedAllExceptAttributesList);
_lockedAllExceptAttributesList.ClearInternal(false);
foreach (string key in intersectionCollection) {
_lockedAllExceptAttributesList.Add(key, ConfigurationValueFlags.Default);
}
}
if (source._lockedElementsList != null) {
if (_lockedElementsList == null) {
_lockedElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElements);
}
ConfigurationElementCollection collection = null;
if (Properties.DefaultCollectionProperty != null) // this is not a collection but it may contain a default collection
{
collection = this[Properties.DefaultCollectionProperty] as ConfigurationElementCollection;
if (collection != null) {
collection.internalElementTagName = source.ElementTagName; // Default collections don't know there tag name
if (collection._lockedElementsList == null) {
collection._lockedElementsList = _lockedElementsList; //point to the same instance of the collection from parent
}
}
}
foreach (string key in source._lockedElementsList) {
_lockedElementsList.Add(key, ConfigurationValueFlags.Inherited); // Mark entry as from the parent - read only
if (collection != null) {
collection._lockedElementsList.Add(key, ConfigurationValueFlags.Inherited); // add the local copy
}
}
}
if (source._lockedAllExceptElementsList != null) {
if (_lockedAllExceptElementsList == null || _lockedAllExceptElementsList.Count == 0) {
_lockedAllExceptElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElementsExceptionList, source._elementTagName, source._lockedAllExceptElementsList);
}
StringCollection intersectionCollection = IntersectLockCollections(_lockedAllExceptElementsList, source._lockedAllExceptElementsList);
ConfigurationElementCollection collection = null;
if (Properties.DefaultCollectionProperty != null) { // this is not a collection but it may contain a default collection
collection = this[Properties.DefaultCollectionProperty] as ConfigurationElementCollection;
if (collection != null && collection._lockedAllExceptElementsList == null) {
// point default collection to the parent collection
collection._lockedAllExceptElementsList = _lockedAllExceptElementsList;
}
}
_lockedAllExceptElementsList.ClearInternal(false);
foreach (string key in intersectionCollection) {
if (!_lockedAllExceptElementsList.Contains(key) || key == ElementTagName)
_lockedAllExceptElementsList.Add(key, ConfigurationValueFlags.Default); // add the local copy
}
if (_lockedAllExceptElementsList.HasParentElements) {
foreach (ConfigurationProperty prop in Properties) {
if ((!_lockedAllExceptElementsList.Contains(prop.Name)) &&
prop.IsConfigurationElementType) {
((ConfigurationElement)this[prop]).SetLocked();
}
}
}
}
}
}
internal void HandleLockedAttributes(ConfigurationElement source) {
// if there are locked attributes on this collection element
if (source != null) {
if (source._lockedAttributesList != null || source._lockedAllExceptAttributesList != null) {
// enumerate the possible locked properties
foreach (PropertyInformation propInfo in source.ElementInformation.Properties) {
if ((source._lockedAttributesList != null && (source._lockedAttributesList.Contains(propInfo.Name) ||
source._lockedAttributesList.Contains(LockAll))) ||
(source._lockedAllExceptAttributesList != null && !source._lockedAllExceptAttributesList.Contains(propInfo.Name))
) {
// if the attribute has been locked in the source then check to see
// if the local config is trying to override it
if (propInfo.Name != LockAttributesKey && propInfo.Name != LockAllAttributesExceptKey) {
if (ElementInformation.Properties[propInfo.Name] == null) { // locked items are not defined
ConfigurationPropertyCollection props = Properties; // so create the property based in the source item
ConfigurationProperty prop = (ConfigurationProperty)source.Properties[propInfo.Name];
props.Add(prop); // Add the property information to the property bag
_evaluationElement = null; // flush the cached element data
// Add the data from the source element but mark it as in herited
// This must use setvalue in order to set the lock and inherited flags
ConfigurationValueFlags flags = ConfigurationValueFlags.Inherited | ConfigurationValueFlags.Locked;
_values.SetValue(propInfo.Name, propInfo.Value, flags, source.PropertyInfoInternal(propInfo.Name));
}
else { // don't error when optional attibute are not defined yet
if (ElementInformation.Properties[propInfo.Name].ValueOrigin == PropertyValueOrigin.SetHere) {
// Don't allow the override
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, propInfo.Name));
}
// They did not override so we need to make sure the value comes from the locked one
ElementInformation.Properties[propInfo.Name].Value = propInfo.Value;
}
}
}
}
}
}
}
// AssociateContext
//
// Associate a context with this element
//
internal virtual void AssociateContext(BaseConfigurationRecord configRecord) {
_configRecord = configRecord;
Values.AssociateContext(configRecord);
}
public /*protected internal virtual*/ ConfigurationLockCollection LockAllAttributesExcept {
get {
if (_lockedAllExceptAttributesList == null) {
_lockedAllExceptAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedExceptionList, _elementTagName);
}
return _lockedAllExceptAttributesList;
}
}
public ConfigurationLockCollection LockElements {
get {
if (_lockedElementsList == null) {
_lockedElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElements);
}
return _lockedElementsList;
}
}
public ConfigurationLockCollection LockAllElementsExcept {
get {
if (_lockedAllExceptElementsList == null) {
_lockedAllExceptElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElementsExceptionList, _elementTagName);
}
return _lockedAllExceptElementsList;
}
}
public bool LockItem {
get {
return ((_fItemLocked & ConfigurationValueFlags.Locked) != 0);
}
set {
if ((_fItemLocked & ConfigurationValueFlags.Inherited) == 0) {
_fItemLocked = (value == true) ? ConfigurationValueFlags.Locked : ConfigurationValueFlags.Default;
_fItemLocked |= ConfigurationValueFlags.Modified;
}
else {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, LockItemKey));
}
}
}
protected internal virtual bool IsModified() {
if (_bModified) {
return true;
}
if (_lockedAttributesList != null && _lockedAttributesList.IsModified) {
return true;
}
if (_lockedAllExceptAttributesList != null && _lockedAllExceptAttributesList.IsModified) {
return true;
}
if (_lockedElementsList != null && _lockedElementsList.IsModified) {
return true;
}
if (_lockedAllExceptElementsList != null && _lockedAllExceptElementsList.IsModified) {
return true;
}
if ((_fItemLocked & ConfigurationValueFlags.Modified) != 0) {
return true;
}
foreach (ConfigurationElement elem in _values.ConfigurationElements) {
if (elem.IsModified()) {
return true;
}
}
return false;
}
protected internal virtual void ResetModified() {
_bModified = false;
if (_lockedAttributesList != null) {
_lockedAttributesList.ResetModified();
}
if (_lockedAllExceptAttributesList != null) {
_lockedAllExceptAttributesList.ResetModified();
}
if (_lockedElementsList != null) {
_lockedElementsList.ResetModified();
}
if (_lockedAllExceptElementsList != null) {
_lockedAllExceptElementsList.ResetModified();
}
foreach (ConfigurationElement elem in _values.ConfigurationElements) {
elem.ResetModified();
}
}
public virtual bool IsReadOnly() {
return _bReadOnly;
}
protected internal virtual void SetReadOnly() {
_bReadOnly = true;
foreach (ConfigurationElement elem in _values.ConfigurationElements) {
elem.SetReadOnly();
}
}
internal void SetLocked() {
_fItemLocked = ConfigurationValueFlags.Locked | ConfigurationValueFlags.XMLParentInherited;
foreach (ConfigurationProperty prop in Properties) {
ConfigurationElement elem = this[prop] as ConfigurationElement;
if (elem != null) {
if (elem.GetType() != this.GetType()) {
elem.SetLocked();
}
ConfigurationElementCollection collection = this[prop] as ConfigurationElementCollection;
if (collection != null) {
foreach (object obj in collection) {
ConfigurationElement element = obj as ConfigurationElement;
if (element != null) {
element.SetLocked();
}
}
}
}
}
}
// GetErrorsList
//
// Get the list of Errors for this location and all
// sub locations
//
internal ArrayList GetErrorsList() {
ArrayList errorList = new ArrayList();
ListErrors(errorList);
return errorList;
}
// GetErrors
//
// Get a ConfigurationErrorsException that contains the errors
// for this ConfigurationElement and its children
//
internal ConfigurationErrorsException GetErrors() {
ArrayList errorsList;
errorsList = GetErrorsList();
if (errorsList.Count == 0) {
return null;
}
ConfigurationErrorsException e = new ConfigurationErrorsException(errorsList);
return e;
}
protected virtual void ListErrors(IList errorList) {
// First list errors in this element, then in subelements
foreach (InvalidPropValue invalidValue in _values.InvalidValues) {
errorList.Add(invalidValue.Error);
}
foreach (ConfigurationElement elem in _values.ConfigurationElements) {
elem.ListErrors(errorList);
ConfigurationElementCollection collection = elem as ConfigurationElementCollection;
if (collection != null) {
foreach (ConfigurationElement item in collection) {
item.ListErrors(errorList);
}
}
}
}
protected internal virtual void InitializeDefault() {
}
internal void CheckLockedElement(string elementName, XmlReader reader) {
// have to check if clear was locked!
if(elementName != null) {
if(((_lockedElementsList != null) &&
(_lockedElementsList.DefinedInParent(LockAll) || _lockedElementsList.DefinedInParent(elementName))) ||
((_lockedAllExceptElementsList != null && _lockedAllExceptElementsList.Count != 0) &&
_lockedAllExceptElementsList.HasParentElements &&
!_lockedAllExceptElementsList.DefinedInParent(elementName) ||
(_fItemLocked & ConfigurationValueFlags.Inherited) != 0)
) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_element_locked, elementName), reader);
}
}
}
internal void RemoveAllInheritedLocks() {
if (_lockedAttributesList != null) {
_lockedAttributesList.RemoveInheritedLocks();
}
if (_lockedElementsList != null) {
_lockedElementsList.RemoveInheritedLocks();
}
if (_lockedAllExceptAttributesList != null) {
_lockedAllExceptAttributesList.RemoveInheritedLocks();
}
if (_lockedAllExceptElementsList != null) {
_lockedAllExceptElementsList.RemoveInheritedLocks();
}
}
internal void ResetLockLists(ConfigurationElement parentElement) {
_lockedAttributesList = null;
_lockedAllExceptAttributesList = null;
_lockedElementsList = null;
_lockedAllExceptElementsList = null;
if (parentElement != null) {
_fItemLocked = ((parentElement._fItemLocked & ConfigurationValueFlags.Locked) != 0) ?
(ConfigurationValueFlags.Inherited | parentElement._fItemLocked) :
ConfigurationValueFlags.Default;
if (parentElement._lockedAttributesList != null) {
_lockedAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedAttributes);
foreach (string key in parentElement._lockedAttributesList)
_lockedAttributesList.Add(key, ConfigurationValueFlags.Inherited); // Mark entry as from the parent - read only
}
if (parentElement._lockedAllExceptAttributesList != null) {
_lockedAllExceptAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedExceptionList, String.Empty, parentElement._lockedAllExceptAttributesList);
}
if (parentElement._lockedElementsList != null) {
_lockedElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElements);
ConfigurationElementCollection collection = null;
if (Properties.DefaultCollectionProperty != null) // this is not a collection but it may contain a default collection
{
collection = this[Properties.DefaultCollectionProperty] as ConfigurationElementCollection;
if (collection != null) {
collection.internalElementTagName = parentElement.ElementTagName; // Default collections don't know there tag name
if (collection._lockedElementsList == null) {
collection._lockedElementsList = _lockedElementsList;
}
}
}
foreach (string key in parentElement._lockedElementsList) {
_lockedElementsList.Add(key, ConfigurationValueFlags.Inherited); // Mark entry as from the parent - read only
}
}
if (parentElement._lockedAllExceptElementsList != null) {
_lockedAllExceptElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElementsExceptionList, parentElement._elementTagName, parentElement._lockedAllExceptElementsList);
ConfigurationElementCollection collection = null;
if (Properties.DefaultCollectionProperty != null) // this is not a collection but it may contain a default collection
{
collection = this[Properties.DefaultCollectionProperty] as ConfigurationElementCollection;
if (collection != null && collection._lockedAllExceptElementsList == null) {
collection._lockedAllExceptElementsList = _lockedAllExceptElementsList;
}
}
}
}
}
protected internal virtual void Reset(ConfigurationElement parentElement) {
Values.Clear();
ResetLockLists(parentElement);
ConfigurationPropertyCollection props = Properties; // Force the bag to be up to date
_bElementPresent = false;
if (parentElement == null) {
InitializeDefault();
}
else {
bool hasAnyChildElements = false;
ConfigurationPropertyCollection collectionKeys = null;
for (int index = 0; index < parentElement.Values.Count; index++) {
string key = parentElement.Values.GetKey(index);
ConfigurationValue ConfigValue = parentElement.Values.GetConfigValue(index);
object value = (ConfigValue != null) ? ConfigValue.Value : null;
PropertySourceInfo sourceInfo = (ConfigValue != null) ? ConfigValue.SourceInfo : null;
ConfigurationProperty prop = (ConfigurationProperty)parentElement.Properties[key];
if (prop == null || ((collectionKeys != null) && !collectionKeys.Contains(prop.Name))) {
continue;
}
if (prop.IsConfigurationElementType) {
hasAnyChildElements = true;
}
else {
ConfigurationValueFlags flags = ConfigurationValueFlags.Inherited |
(((_lockedAttributesList != null) &&
(_lockedAttributesList.Contains(key) ||
_lockedAttributesList.Contains(LockAll)) ||
(_lockedAllExceptAttributesList != null) &&
!_lockedAllExceptAttributesList.Contains(key)) ?
ConfigurationValueFlags.Locked : ConfigurationValueFlags.Default);
if (value != s_nullPropertyValue) {
// _values[key] = value;
_values.SetValue(key, value, flags, sourceInfo);
}
if (!props.Contains(key)) // this is for optional provider models keys
{
props.Add(prop);
_values.SetValue(key, value, flags, sourceInfo);
}
}
}
if (hasAnyChildElements) {
for (int index = 0; index < parentElement.Values.Count; index++) {
string key = parentElement.Values.GetKey(index);
object value = parentElement.Values[index];
ConfigurationProperty prop = (ConfigurationProperty)parentElement.Properties[key];
if ((prop != null) && prop.IsConfigurationElementType) {
//((ConfigurationElement)value).SerializeToXmlElement(writer, prop.Name);
ConfigurationElement childElement = (ConfigurationElement)this[prop];
childElement.Reset((ConfigurationElement)value);
}
}
}
}
}
public override bool Equals(object compareTo) {
ConfigurationElement compareToElem = compareTo as ConfigurationElement;
if (compareToElem == null ||
(compareTo.GetType() != this.GetType()) ||
((compareToElem != null) && (compareToElem.Properties.Count != this.Properties.Count))) {
return false;
}
foreach (ConfigurationProperty configProperty in this.Properties) {
if (!Object.Equals(Values[configProperty.Name], compareToElem.Values[configProperty.Name])) {
if (!(((Values[configProperty.Name] == null ||
Values[configProperty.Name] == s_nullPropertyValue) &&
Object.Equals(compareToElem.Values[configProperty.Name], configProperty.DefaultValue)) ||
((compareToElem.Values[configProperty.Name] == null ||
compareToElem.Values[configProperty.Name] == s_nullPropertyValue) &&
Object.Equals(Values[configProperty.Name], configProperty.DefaultValue))))
return false;
}
}
return true;
}
public override int GetHashCode() {
int hHashCode = 0;
foreach (ConfigurationProperty configProperty in this.Properties) {
object o = this[configProperty];
if (o != null) {
hHashCode ^= this[configProperty].GetHashCode();
}
}
return hHashCode;
}
protected internal Object this[ConfigurationProperty prop] {
get {
Object o = _values[prop.Name];
if (o == null) {
if (prop.IsConfigurationElementType) {
lock (_values.SyncRoot) {
o = _values[prop.Name];
if (o == null) {
ConfigurationElement childElement = CreateElement(prop.Type);
if (_bReadOnly) {
childElement.SetReadOnly();
}
if (typeof(ConfigurationElementCollection).IsAssignableFrom(prop.Type)) {
ConfigurationElementCollection childElementCollection = childElement as ConfigurationElementCollection;
if (prop.AddElementName != null)
childElementCollection.AddElementName = prop.AddElementName;
if (prop.RemoveElementName != null)
childElementCollection.RemoveElementName = prop.RemoveElementName;
if (prop.ClearElementName != null)
childElementCollection.ClearElementName = prop.ClearElementName;
}
//_values[prop.Name] = childElement;
_values.SetValue(prop.Name, childElement, ConfigurationValueFlags.Inherited, null);
o = childElement;
}
}
}
else {
o = prop.DefaultValue;
}
}
else if (o == s_nullPropertyValue) {
o = null;
}
// If its an invalid value - throw the error now
if (o is InvalidPropValue) {
throw ((InvalidPropValue)o).Error;
}
return o;
}
set {
SetPropertyValue(prop, value,false); // Do not ignore locks!!!
}
}
protected internal Object this[String propertyName] {
get {
ConfigurationProperty prop = Properties[propertyName];
if (prop == null) {
prop = Properties[DefaultCollectionPropertyName];
if (prop.ProvidedName != propertyName) {
return null;
}
}
return this[prop];
}
set {
Debug.Assert(Properties.Contains(propertyName), "Properties.Contains(propertyName)");
SetPropertyValue(Properties[propertyName], value, false);// Do not ignore locks!!!
}
}
// Note: this method is completelly redundant ( the code is duplaicated in ConfigurationProperty( PropertyInfo ) )
// We do not remove the code now to minimize code changes for Whidbey RTM but this method and all calls leading to it should
// be removed post-Whidbey
private static void ApplyInstanceAttributes(object instance) {
Debug.Assert(instance is ConfigurationElement, "instance is ConfigurationElement");
Type type = instance.GetType();
foreach (PropertyInfo propertyInformation in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
ConfigurationPropertyAttribute attribProperty =
Attribute.GetCustomAttribute(propertyInformation,
typeof(ConfigurationPropertyAttribute)) as ConfigurationPropertyAttribute;
if (attribProperty != null)
{
Type propertyType = propertyInformation.PropertyType;
// Collections need some customization when the collection attribute is present
if (typeof(ConfigurationElementCollection).IsAssignableFrom(propertyType)) {
ConfigurationCollectionAttribute attribCollection =
Attribute.GetCustomAttribute(propertyInformation,
typeof(ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute;
// If none on the property - see if there is an attribute on the collection type itself
if (attribCollection == null) {
attribCollection =
Attribute.GetCustomAttribute(propertyType,
typeof(ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute;
}
ConfigurationElementCollection coll = propertyInformation.GetValue(instance, null) as ConfigurationElementCollection;
if (coll == null) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_element_null_instance,
propertyInformation.Name, attribProperty.Name));
}
// If the attribute is found - get the collection instance and set the data from the attribute
if (attribCollection != null) {
if (attribCollection.AddItemName.IndexOf(',') == -1) {
coll.AddElementName = attribCollection.AddItemName;
}
coll.RemoveElementName = attribCollection.RemoveItemName;
coll.ClearElementName = attribCollection.ClearItemsName;
}
}
else if (typeof(ConfigurationElement).IsAssignableFrom(propertyType)) {
// Nested configuration element - handle recursively
object element = propertyInformation.GetValue(instance, null);
if (element == null) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_element_null_instance,
propertyInformation.Name,attribProperty.Name));
}
ApplyInstanceAttributes(element);
}
}
}
}
private static bool PropertiesFromType(Type type, out ConfigurationPropertyCollection result) {
ConfigurationPropertyCollection properties = (ConfigurationPropertyCollection)s_propertyBags[type];
result = null;
bool firstTimeInit = false;
if (properties == null) {
lock (s_propertyBags.SyncRoot) {
properties = (ConfigurationPropertyCollection)s_propertyBags[type];
if (properties == null) {
properties = CreatePropertyBagFromType(type);
s_propertyBags[type] = properties;
firstTimeInit = true;
}
}
}
result = properties;
return firstTimeInit;
}
private static ConfigurationPropertyCollection CreatePropertyBagFromType(Type type) {
Debug.Assert(type != null, "type != null");
// For ConfigurationElement derived classes - get the per-type validator
if (typeof(ConfigurationElement).IsAssignableFrom(type)) {
ConfigurationValidatorAttribute attribValidator = Attribute.GetCustomAttribute(type, typeof(ConfigurationValidatorAttribute)) as ConfigurationValidatorAttribute;
if (attribValidator != null) {
attribValidator.SetDeclaringType(type);
ConfigurationValidatorBase validator = attribValidator.ValidatorInstance;
if (validator != null) {
CachePerTypeValidator(type, validator);
}
}
}
ConfigurationPropertyCollection properties = new ConfigurationPropertyCollection();
foreach (PropertyInfo propertyInformation in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
ConfigurationProperty newProp = CreateConfigurationPropertyFromAttributes(propertyInformation);
if (newProp != null) {
properties.Add(newProp);
}
}
return properties;
}
private static ConfigurationProperty CreateConfigurationPropertyFromAttributes(PropertyInfo propertyInformation) {
Debug.Assert(propertyInformation != null, "propertyInformation != null");
ConfigurationProperty result = null;
ConfigurationPropertyAttribute attribProperty =
Attribute.GetCustomAttribute(propertyInformation,
typeof(ConfigurationPropertyAttribute)) as ConfigurationPropertyAttribute;
// If there is no ConfigurationProperty attrib - this is not considered a property
if (attribProperty != null) {
result = new ConfigurationProperty(propertyInformation);
}
// Handle some special cases of property types
if (result != null && typeof(ConfigurationElement).IsAssignableFrom(result.Type)) {
ConfigurationPropertyCollection unused = null;
PropertiesFromType(result.Type, out unused);
}
return result;
}
private static void CachePerTypeValidator( Type type, ConfigurationValidatorBase validator ) {
Debug.Assert((type != null) && ( validator != null));
Debug.Assert(typeof(ConfigurationElement).IsAssignableFrom(type));
// Use the same lock as the property bag lock since in the current implementation
// the only way to get to this method is through the code path that locks the property bag cache first ( see PropertiesFromType() )
// NOTE[ Thread Safety ]: Non-guarded access to static variable - since this code is called only from CreatePropertyBagFromType
// which in turn is done onle once per type and is guarded by the s_propertyBag.SyncRoot then this call is thread safe as well
if (s_perTypeValidators == null ) {
s_perTypeValidators = new Dictionary<Type,ConfigurationValidatorBase>();
}
// A type validator should be cached only once. If it isn't then attribute parsing is done more then once which should be avoided
Debug.Assert( !s_perTypeValidators.ContainsKey(type));
// Make sure the supplied validator supports validating this object
if (!validator.CanValidate(type)) {
throw new ConfigurationErrorsException(SR.GetString(SR.Validator_does_not_support_elem_type,
type.Name));
}
s_perTypeValidators.Add(type, validator);
}
private static void ApplyValidatorsRecursive(ConfigurationElement root) {
Debug.Assert(root != null);
// Apply the validator on 'root'
ApplyValidator(root);
// Apply validators on child elements ( note - we will do this only on already created child elements
// The non created ones will get their validators in the ctor
foreach (ConfigurationElement elem in root._values.ConfigurationElements) {
ApplyValidatorsRecursive(elem);
}
}
private static void ApplyValidator(ConfigurationElement elem) {
Debug.Assert(elem != null);
if ((s_perTypeValidators != null) && (s_perTypeValidators.ContainsKey(elem.GetType()))) {
elem._elementProperty = new ConfigurationElementProperty(s_perTypeValidators[ elem.GetType() ]);
}
}
protected void SetPropertyValue(ConfigurationProperty prop, object value, bool ignoreLocks) {
if (IsReadOnly()) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
}
if ((ignoreLocks == false) &&
((_lockedAllExceptAttributesList != null && _lockedAllExceptAttributesList.HasParentElements && !_lockedAllExceptAttributesList.DefinedInParent(prop.Name)) ||
(_lockedAttributesList != null && (_lockedAttributesList.DefinedInParent(prop.Name) || _lockedAttributesList.DefinedInParent(LockAll))) ||
((_fItemLocked & ConfigurationValueFlags.Locked) != 0) &&
(_fItemLocked & ConfigurationValueFlags.Inherited) != 0)) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, prop.Name));
}
_bModified = true;
// Run the new value through the validator to make sure its ok to store it
if (value != null) {
prop.Validate(value);
}
_values[prop.Name] = (value != null) ? value : s_nullPropertyValue;
}
protected internal virtual ConfigurationPropertyCollection Properties {
get {
ConfigurationPropertyCollection result = null;
if (PropertiesFromType(this.GetType(), out result)) {
ApplyInstanceAttributes(this); // Redundant but preserved to minimize code changes for Whidbey RTM
ApplyValidatorsRecursive(this);
}
return result;
}
}
internal ConfigurationValues Values {
get {
return _values;
}
}
internal PropertySourceInfo PropertyInfoInternal(string propertyName) {
return (PropertySourceInfo)_values.GetSourceInfo(propertyName);
}
internal string PropertyFileName(string propertyName) {
PropertySourceInfo p = (PropertySourceInfo)PropertyInfoInternal(propertyName);
if (p == null)
p = (PropertySourceInfo)PropertyInfoInternal(String.Empty); // Get the filename of the parent if prop is not there
if (p == null)
return String.Empty;
return p.FileName;
}
internal int PropertyLineNumber(string propertyName) {
PropertySourceInfo p = (PropertySourceInfo)PropertyInfoInternal(propertyName);
if (p == null)
p = (PropertySourceInfo)PropertyInfoInternal(String.Empty);
if (p == null)
return 0;
return p.LineNumber;
}
internal virtual void Dump(TextWriter tw) {
tw.WriteLine("Type: " + GetType().FullName);
foreach (PropertyInfo pi in GetType().GetProperties()) {
tw.WriteLine("{0}: {1}", pi.Name, pi.GetValue(this, null));
}
}
protected internal virtual void Unmerge(ConfigurationElement sourceElement,
ConfigurationElement parentElement,
ConfigurationSaveMode saveMode) {
if (sourceElement != null) {
bool hasAnyChildElements = false;
_lockedAllExceptAttributesList = sourceElement._lockedAllExceptAttributesList;
_lockedAllExceptElementsList = sourceElement._lockedAllExceptElementsList;
_fItemLocked = sourceElement._fItemLocked;
_lockedAttributesList = sourceElement._lockedAttributesList;
_lockedElementsList = sourceElement._lockedElementsList;
AssociateContext(sourceElement._configRecord);
if (parentElement != null) {
if (parentElement._lockedAttributesList != null)
_lockedAttributesList = UnMergeLockList(sourceElement._lockedAttributesList,
parentElement._lockedAttributesList, saveMode);
if (parentElement._lockedElementsList != null)
_lockedElementsList = UnMergeLockList(sourceElement._lockedElementsList,
parentElement._lockedElementsList, saveMode);
if (parentElement._lockedAllExceptAttributesList != null)
_lockedAllExceptAttributesList = UnMergeLockList(sourceElement._lockedAllExceptAttributesList,
parentElement._lockedAllExceptAttributesList, saveMode);
if (parentElement._lockedAllExceptElementsList != null)
_lockedAllExceptElementsList = UnMergeLockList(sourceElement._lockedAllExceptElementsList,
parentElement._lockedAllExceptElementsList, saveMode);
}
ConfigurationPropertyCollection props = Properties;
ConfigurationPropertyCollection collectionKeys = null;
// check for props not in bag from source
for (int index = 0; index < sourceElement.Values.Count; index++) {
string key = sourceElement.Values.GetKey(index);
object value = sourceElement.Values[index];
ConfigurationProperty prop = (ConfigurationProperty)sourceElement.Properties[key];
if (prop == null || (collectionKeys != null && !collectionKeys.Contains(prop.Name)))
continue;
if (prop.IsConfigurationElementType) {
hasAnyChildElements = true;
}
else {
if (value != s_nullPropertyValue) {
if (!props.Contains(key)) // this is for optional provider models keys
{
// _values[key] = value;
ConfigurationValueFlags valueFlags = sourceElement.Values.RetrieveFlags(key);
_values.SetValue(key, value, valueFlags, null);
props.Add(prop);
}
}
}
}
foreach (ConfigurationProperty prop in Properties) {
if (prop == null || (collectionKeys != null && !collectionKeys.Contains(prop.Name))) {
continue;
}
if (prop.IsConfigurationElementType) {
hasAnyChildElements = true;
}
else {
object value = sourceElement.Values[prop.Name];
// if the property is required or we are writing a full config make sure we have defaults
if ((prop.IsRequired == true || saveMode == ConfigurationSaveMode.Full) && (value == null || value == s_nullPropertyValue)) {
// If the default value is null, this means there wasnt a reasonable default for the value
// and there is nothing more we can do. Otherwise reset the value to the default
// Note: 'null' should be used as default for non-empty strings instead
// of the current practice to use String.Epmty
if (prop.DefaultValue != null) {
value = prop.DefaultValue; // need to make sure required properties are persisted
}
}
if (value != null && value != s_nullPropertyValue) {
object value2 = null;
if (parentElement != null) // Is there a parent
value2 = parentElement.Values[prop.Name]; // if so get it's value
if (value2 == null) // no parent use default
value2 = prop.DefaultValue;
// If changed and not same as parent write or required
switch (saveMode) {
case ConfigurationSaveMode.Minimal: {
if (!Object.Equals(value, value2) || prop.IsRequired == true)
_values[prop.Name] = value;
}
break;
// (value != null && value != s_nullPropertyValue) ||
case ConfigurationSaveMode.Modified: {
bool modified = sourceElement.Values.IsModified(prop.Name);
bool inherited = sourceElement.Values.IsInherited(prop.Name);
// update the value if the property is required, modified or it was not inherited
// Also update properties that ARE inherited when we are resetting the object
// as long as the property is not the same as the default value for the property
if ((prop.IsRequired || modified || !inherited) ||
(parentElement == null && inherited && !Object.Equals(value, value2))) {
_values[prop.Name] = value;
}
}
break;
case ConfigurationSaveMode.Full: {
if (value != null && value != s_nullPropertyValue)
_values[prop.Name] = value;
else
_values[prop.Name] = value2;
}
break;
}
}
}
}
if (hasAnyChildElements) {
foreach (ConfigurationProperty prop in Properties) {
if (prop.IsConfigurationElementType) {
ConfigurationElement pElem = (ConfigurationElement)((parentElement != null) ? parentElement[prop] : null);
ConfigurationElement childElement = (ConfigurationElement)this[prop];
if ((ConfigurationElement)sourceElement[prop] != null)
childElement.Unmerge((ConfigurationElement)sourceElement[prop],
pElem, saveMode);
}
}
}
}
}
protected internal virtual bool SerializeToXmlElement(XmlWriter writer, String elementName) {
if (_configRecord != null && _configRecord.TargetFramework != null) {
ConfigurationSection section = null;
if (_configRecord.SectionsStack.Count >0) {
section = _configRecord.SectionsStack.Peek() as ConfigurationSection;
}
if (section != null && !section.ShouldSerializeElementInTargetVersion(this, elementName, _configRecord.TargetFramework)) {
return false;
}
}
bool DataToWrite = _bDataToWrite;
// Don't write elements that are locked in the parent
if ((_lockedElementsList != null && _lockedElementsList.DefinedInParent(elementName)) ||
(_lockedAllExceptElementsList != null && _lockedAllExceptElementsList.HasParentElements && !_lockedAllExceptElementsList.DefinedInParent(elementName))) {
return DataToWrite;
}
if (SerializeElement(null, false) == true) // check if there is anything to write...
{
if (writer != null)
writer.WriteStartElement(elementName);
DataToWrite |= SerializeElement(writer, false);
if (writer != null)
writer.WriteEndElement();
}
return DataToWrite;
}
protected internal virtual bool SerializeElement(XmlWriter writer, bool serializeCollectionKey) {
PreSerialize(writer);
bool DataToWrite = _bDataToWrite;
bool hasAnyChildElements = false;
bool foundDefaultElement = false;
ConfigurationPropertyCollection props = Properties;
ConfigurationPropertyCollection collectionKeys = null;
for (int index = 0; index < _values.Count; index++) {
string key = _values.GetKey(index);
object value = _values[index];
ConfigurationProperty prop = (ConfigurationProperty)props[key];
if (prop == null || (collectionKeys != null && !collectionKeys.Contains(prop.Name))) {
continue;
}
if ( prop.IsVersionCheckRequired && _configRecord != null && _configRecord.TargetFramework != null) {
ConfigurationSection section = null;
if (_configRecord.SectionsStack.Count >0) {
section = _configRecord.SectionsStack.Peek() as ConfigurationSection;
}
if (section != null && !section.ShouldSerializePropertyInTargetVersion(prop, prop.Name, _configRecord.TargetFramework, this)) {
continue;
}
}
if (prop.IsConfigurationElementType) {
hasAnyChildElements = true;
}
else {
if ((_lockedAllExceptAttributesList != null && _lockedAllExceptAttributesList.HasParentElements && !_lockedAllExceptAttributesList.DefinedInParent(prop.Name)) ||
(_lockedAttributesList != null && _lockedAttributesList.DefinedInParent(prop.Name))) {
if (prop.IsRequired == true)
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_required_attribute_locked, prop.Name));
value = s_nullPropertyValue;
}
if (value != s_nullPropertyValue) {
if (serializeCollectionKey == false || prop.IsKey == true) {
string xmlValue = null;
// If this was an invalid string value and was cached - write it out as is
if (value is InvalidPropValue) {
xmlValue = ((InvalidPropValue)value).Value;
}
else {
prop.Validate(value);
xmlValue = prop.ConvertToString(value);
}
if ((xmlValue != null) && (writer != null)) {
if (prop.IsTypeStringTransformationRequired)
xmlValue = GetTransformedTypeString(xmlValue);
if (prop.IsAssemblyStringTransformationRequired)
xmlValue = GetTransformedAssemblyString(xmlValue);
writer.WriteAttributeString(prop.Name, xmlValue);
}
DataToWrite = DataToWrite || (xmlValue != null);
}
}
}
}
if (serializeCollectionKey == false) {
DataToWrite |= SerializeLockList(_lockedAttributesList, LockAttributesKey, writer);
DataToWrite |= SerializeLockList(_lockedAllExceptAttributesList, LockAllAttributesExceptKey, writer);
DataToWrite |= SerializeLockList(_lockedElementsList, LockElementsKey, writer);
DataToWrite |= SerializeLockList(_lockedAllExceptElementsList, LockAllElementsExceptKey, writer);
if ((_fItemLocked & ConfigurationValueFlags.Locked) != 0 &&
(_fItemLocked & ConfigurationValueFlags.Inherited) == 0 &&
(_fItemLocked & ConfigurationValueFlags.XMLParentInherited) == 0) {
DataToWrite = true;
if (writer != null)
writer.WriteAttributeString(LockItemKey, true.ToString().ToLower(CultureInfo.InvariantCulture));
}
}
if (hasAnyChildElements) {
for (int index = 0; index < _values.Count; index++) {
string key = _values.GetKey(index);
object value = _values[index];
ConfigurationProperty prop = (ConfigurationProperty)props[key];
// if we are writing a remove and the sub element is not part of the key don't write it.
if (serializeCollectionKey == false || prop.IsKey == true) {
if (value is ConfigurationElement) {
if (!((_lockedElementsList != null && _lockedElementsList.DefinedInParent(key)) ||
(_lockedAllExceptElementsList != null && _lockedAllExceptElementsList.HasParentElements && !_lockedAllExceptElementsList.DefinedInParent(key)))) {
ConfigurationElement elem = (ConfigurationElement)value;
if (prop.Name != ConfigurationProperty.DefaultCollectionPropertyName) {
DataToWrite |= elem.SerializeToXmlElement(writer, prop.Name);
}
else if (!foundDefaultElement) {
// Prevent the locks from serializing a second time since locks
// on a default collection serialize with their parent node
elem._lockedAttributesList = null;
elem._lockedAllExceptAttributesList = null;
elem._lockedElementsList = null;
elem._lockedAllExceptElementsList = null;
DataToWrite |= elem.SerializeElement(writer, false);
foundDefaultElement = true;
}
else {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_element_cannot_have_multiple_child_elements, prop.Name));
}
}
}
}
}
}
return DataToWrite;
}
private bool SerializeLockList(ConfigurationLockCollection list, String elementKey, XmlWriter writer) {
StringBuilder sb;
sb = new StringBuilder();
if (list != null) {
foreach (string key in list) {
if (!list.DefinedInParent(key)) {
if (sb.Length != 0)
sb.Append(',');
sb.Append((string)key);
}
}
}
if (writer != null && sb.Length != 0)
writer.WriteAttributeString(elementKey, sb.ToString());
return (sb.Length != 0);
}
internal void ReportInvalidLock(string attribToLockTrim, ConfigurationLockCollectionType lockedType, ConfigurationValue value, String collectionProperties) {
StringBuilder sb;
sb = new StringBuilder();
// Add the collection properties when locking elements
if (!String.IsNullOrEmpty(collectionProperties) &&
((lockedType == ConfigurationLockCollectionType.LockedElements) || (lockedType == ConfigurationLockCollectionType.LockedElementsExceptionList))) {
if (sb.Length != 0)
sb.Append(',');
sb.Append(collectionProperties);
}
// construct a list of valid lockable properties
foreach (object _prop in Properties) {
ConfigurationProperty validProp = (ConfigurationProperty)_prop;
if (validProp.Name != LockAttributesKey &&
validProp.Name != LockAllAttributesExceptKey &&
validProp.Name != LockElementsKey &&
validProp.Name != LockAllElementsExceptKey
) {
if ((lockedType == ConfigurationLockCollectionType.LockedElements) ||
(lockedType == ConfigurationLockCollectionType.LockedElementsExceptionList)) {
if (typeof(ConfigurationElement).IsAssignableFrom(validProp.Type)) {
if (sb.Length != 0)
sb.Append(", ");
sb.Append("'");
sb.Append(validProp.Name);
sb.Append("'");
}
}
else {
if (!typeof(ConfigurationElement).IsAssignableFrom(validProp.Type)) {
if (sb.Length != 0)
sb.Append(", ");
sb.Append("'");
sb.Append(validProp.Name);
sb.Append("'");
}
}
}
}
string format = null;
if ((lockedType == ConfigurationLockCollectionType.LockedElements) ||
(lockedType == ConfigurationLockCollectionType.LockedElementsExceptionList)) {
if (value != null)
format = SR.GetString(SR.Config_base_invalid_element_to_lock);
else
format = SR.GetString(SR.Config_base_invalid_element_to_lock_by_add);
}
else {
if (value != null)
format = SR.GetString(SR.Config_base_invalid_attribute_to_lock);
else
format = SR.GetString(SR.Config_base_invalid_attribute_to_lock_by_add);
}
if (value != null)
throw new ConfigurationErrorsException(string.Format(CultureInfo.CurrentCulture, format, attribToLockTrim, sb.ToString()), value.SourceInfo.FileName, value.SourceInfo.LineNumber);
else
throw new ConfigurationErrorsException(string.Format(CultureInfo.CurrentCulture, format, attribToLockTrim, sb.ToString()));
}
private ConfigurationLockCollection ParseLockedAttributes(ConfigurationValue value, ConfigurationLockCollectionType lockType) {
// check that only actual properties are in the lock attribute
ConfigurationLockCollection localLockedAttributesList = new ConfigurationLockCollection(this, lockType);
string attributeList = (string)(value.Value);
if (string.IsNullOrEmpty(attributeList)) {
if (lockType == ConfigurationLockCollectionType.LockedAttributes)
throw new ConfigurationErrorsException(SR.GetString(SR.Empty_attribute, LockAttributesKey), value.SourceInfo.FileName, value.SourceInfo.LineNumber);
if (lockType == ConfigurationLockCollectionType.LockedElements)
throw new ConfigurationErrorsException(SR.GetString(SR.Empty_attribute, LockElementsKey), value.SourceInfo.FileName, value.SourceInfo.LineNumber);
if (lockType == ConfigurationLockCollectionType.LockedExceptionList)
throw new ConfigurationErrorsException(SR.GetString(SR.Config_empty_lock_attributes_except, LockAllAttributesExceptKey, LockAttributesKey), value.SourceInfo.FileName, value.SourceInfo.LineNumber);
if (lockType == ConfigurationLockCollectionType.LockedElementsExceptionList)
throw new ConfigurationErrorsException(SR.GetString(SR.Config_empty_lock_element_except, LockAllElementsExceptKey, LockElementsKey), value.SourceInfo.FileName, value.SourceInfo.LineNumber);
}
string[] attribsToLock = attributeList.Split(new char[] { ',', ':', ';' });
foreach (string attribToLock in attribsToLock) {
string attribToLockTrim = attribToLock.Trim();
if (!String.IsNullOrEmpty(attribToLockTrim)) {
// validate that the locks are good
if (!((lockType == ConfigurationLockCollectionType.LockedElements ||
lockType == ConfigurationLockCollectionType.LockedAttributes) &&
attribToLockTrim == LockAll)) {
ConfigurationProperty propToLock = Properties[attribToLockTrim];
if (propToLock == null || // if the prop does not exist
attribToLockTrim == LockAttributesKey || // or it is the lockattributes keyword
attribToLockTrim == LockAllAttributesExceptKey || // or it is the lockattributes keyword
attribToLockTrim == LockElementsKey || // or it is the lockelements keyword
(lockType != ConfigurationLockCollectionType.LockedElements && lockType != ConfigurationLockCollectionType.LockedElementsExceptionList &&
typeof(ConfigurationElement).IsAssignableFrom(propToLock.Type)) || // or if not locking elements but the property is a element
((lockType == ConfigurationLockCollectionType.LockedElements || lockType == ConfigurationLockCollectionType.LockedElementsExceptionList) &&
!typeof(ConfigurationElement).IsAssignableFrom(propToLock.Type)) // or if locking elements but the property is not an element
) {
// check to see if this is a collection and we are locking a collection element
ConfigurationElementCollection collection = this as ConfigurationElementCollection;
if (collection == null && Properties.DefaultCollectionProperty != null) // this is not a collection but it may contain a default collection
{
collection = this[Properties.DefaultCollectionProperty] as ConfigurationElementCollection;
}
if (collection == null ||
lockType == ConfigurationLockCollectionType.LockedAttributes || // If the collection type is not element then the lock is bogus
lockType == ConfigurationLockCollectionType.LockedExceptionList) {
ReportInvalidLock(attribToLockTrim, lockType, value, null);
}
else if (!collection.IsLockableElement(attribToLockTrim)) {
ReportInvalidLock(attribToLockTrim, lockType, value, collection.LockableElements);
}
}
if (propToLock != null && propToLock.IsRequired == true)
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_required_attribute_lock_attempt, propToLock.Name));
}
// concatenate the new attribute.
localLockedAttributesList.Add(attribToLockTrim, ConfigurationValueFlags.Default); // Mark as local
}
}
return localLockedAttributesList;
}
private StringCollection IntersectLockCollections(ConfigurationLockCollection Collection1, ConfigurationLockCollection Collection2) {
ConfigurationLockCollection smallCollection = Collection1.Count < Collection2.Count ? Collection1 : Collection2;
ConfigurationLockCollection largeCollection = Collection1.Count >= Collection2.Count ? Collection1 : Collection2;
StringCollection intersectionCollection = new StringCollection();
foreach (string key in smallCollection) {
if (largeCollection.Contains(key) || key == ElementTagName)
intersectionCollection.Add(key); // add the local copy
}
return intersectionCollection;
}
protected internal virtual void DeserializeElement(XmlReader reader, bool serializeCollectionKey) {
ConfigurationPropertyCollection props = Properties;
ConfigurationValue LockedAttributesList = null;
ConfigurationValue LockedAllExceptList = null;
ConfigurationValue LockedElementList = null;
ConfigurationValue LockedAllElementsExceptList = null;
bool ItemLockedLocally = false;
_bElementPresent = true;
ConfigurationElement defaultCollection = null;
ConfigurationProperty defaultCollectionProperty = props != null ? props.DefaultCollectionProperty : null;
if (defaultCollectionProperty != null) {
defaultCollection = (ConfigurationElement)this[defaultCollectionProperty];
}
// Process attributes
_elementTagName = reader.Name;
PropertySourceInfo rootInfo = new PropertySourceInfo(reader);
_values.SetValue(reader.Name, null, ConfigurationValueFlags.Modified, rootInfo);
_values.SetValue(DefaultCollectionPropertyName, defaultCollection, ConfigurationValueFlags.Modified, rootInfo);
if ((_lockedElementsList != null && (_lockedElementsList.Contains(reader.Name) ||
(_lockedElementsList.Contains(LockAll) && reader.Name != ElementTagName))) ||
(_lockedAllExceptElementsList != null && _lockedAllExceptElementsList.Count != 0 && !_lockedAllExceptElementsList.Contains(reader.Name)) ||
((_fItemLocked & ConfigurationValueFlags.Locked) != 0 && (_fItemLocked & ConfigurationValueFlags.Inherited) != 0)
) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_element_locked, reader.Name), reader);
}
if (reader.AttributeCount > 0) {
while (reader.MoveToNextAttribute()) {
String propertyName = reader.Name;
if ((_lockedAttributesList != null && (_lockedAttributesList.Contains(propertyName) || _lockedAttributesList.Contains(LockAll))) ||
(_lockedAllExceptAttributesList != null && !_lockedAllExceptAttributesList.Contains(propertyName))
) {
if (propertyName != LockAttributesKey && propertyName != LockAllAttributesExceptKey)
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, propertyName), reader);
}
ConfigurationProperty prop = props != null ? props[propertyName] : null;
if (prop != null) {
if (serializeCollectionKey && !prop.IsKey) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_unrecognized_attribute, propertyName), reader);
}
_values.SetValue(propertyName,
DeserializePropertyValue(prop, reader),
ConfigurationValueFlags.Modified,
new PropertySourceInfo(reader));
} // if (deserializing a remove OR an add that does not handle optional attributes)
else if (propertyName == LockItemKey) {
try {
ItemLockedLocally = bool.Parse(reader.Value);
}
catch {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_invalid_boolean_attribute, propertyName), reader);
}
}
else if (propertyName == LockAttributesKey) {
LockedAttributesList = new ConfigurationValue(reader.Value, ConfigurationValueFlags.Default, new PropertySourceInfo(reader));
}
else if (propertyName == LockAllAttributesExceptKey) {
LockedAllExceptList = new ConfigurationValue(reader.Value, ConfigurationValueFlags.Default, new PropertySourceInfo(reader));
}
else if (propertyName == LockElementsKey) {
LockedElementList = new ConfigurationValue(reader.Value, ConfigurationValueFlags.Default, new PropertySourceInfo(reader));
}
else if (propertyName == LockAllElementsExceptKey) {
LockedAllElementsExceptList = new ConfigurationValue(reader.Value, ConfigurationValueFlags.Default, new PropertySourceInfo(reader));
}
else if (serializeCollectionKey || !OnDeserializeUnrecognizedAttribute(propertyName, reader.Value)) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_unrecognized_attribute, propertyName), reader);
}
}
}
reader.MoveToElement();
// Check for nested elements.
try {
HybridDictionary nodeFound = new HybridDictionary();
if (!reader.IsEmptyElement) {
while (reader.Read()) {
if (reader.NodeType == XmlNodeType.Element) {
String propertyName = reader.Name;
CheckLockedElement(propertyName, null);
ConfigurationProperty prop = props != null ? props[propertyName] : null;
if (prop != null) {
if (prop.IsConfigurationElementType) {
//
if (nodeFound.Contains(propertyName))
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_element_cannot_have_multiple_child_elements, propertyName), reader);
nodeFound.Add(propertyName, propertyName);
ConfigurationElement childElement = (ConfigurationElement)this[prop];
childElement.DeserializeElement(reader, serializeCollectionKey);
// Validate the new element with the per-property Validator
// Note that the per-type validator for childElement has been already executed as part of Deserialize
ValidateElement(childElement, prop.Validator, false);
}
else {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_property_is_not_a_configuration_element, propertyName), reader);
}
}
else if (!OnDeserializeUnrecognizedElement(propertyName, reader)) {
// Let the default collection, if there is one, handle this node.
if (defaultCollection == null ||
!defaultCollection.OnDeserializeUnrecognizedElement(propertyName, reader)) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_unrecognized_element_name, propertyName), reader);
}
}
}
else if (reader.NodeType == XmlNodeType.EndElement) {
break;
}
else if ((reader.NodeType == XmlNodeType.CDATA) || (reader.NodeType == XmlNodeType.Text)) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_section_invalid_content), reader);
}
}
}
EnsureRequiredProperties(serializeCollectionKey);
// Call the per-type validator for this object
ValidateElement(this, null, false);
}
catch (ConfigurationException e) {
// Catch the generic message from deserialization and include line info if necessary
if (e.Filename == null || e.Filename.Length == 0)
throw new ConfigurationErrorsException(e.Message, reader); // give it some info
else
throw e;
}
if (ItemLockedLocally) {
SetLocked();
_fItemLocked = ConfigurationValueFlags.Locked;
}
if (LockedAttributesList != null) {
if (_lockedAttributesList == null)
_lockedAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedAttributes);
foreach (string key in ParseLockedAttributes(LockedAttributesList, ConfigurationLockCollectionType.LockedAttributes)) {
if (!_lockedAttributesList.Contains(key))
_lockedAttributesList.Add(key, ConfigurationValueFlags.Default); // add the local copy
else
_lockedAttributesList.Add(key, ConfigurationValueFlags.Modified | ConfigurationValueFlags.Inherited); // add the local copy
}
}
if (LockedAllExceptList != null) {
ConfigurationLockCollection newCollection = ParseLockedAttributes(LockedAllExceptList, ConfigurationLockCollectionType.LockedExceptionList);
if (_lockedAllExceptAttributesList == null) {
_lockedAllExceptAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedExceptionList, String.Empty, newCollection);
_lockedAllExceptAttributesList.ClearSeedList(); // Prevent the list from thinking this was set by a parent.
}
StringCollection intersectionCollection = IntersectLockCollections(_lockedAllExceptAttributesList, newCollection);
/*
if (intersectionCollection.Count == 0) {
throw new ConfigurationErrorsException(SR.GetString(SR.Config_empty_lock_attributes_except_effective,
LockAllAttributesExceptKey,
LockedAllExceptList.Value,
LockAttributesKey),
LockedAllExceptList.SourceInfo.FileName,
LockedAllExceptList.SourceInfo.LineNumber);
}
*/
_lockedAllExceptAttributesList.ClearInternal(false);
foreach (string key in intersectionCollection) {
_lockedAllExceptAttributesList.Add(key, ConfigurationValueFlags.Default);
}
}
if (LockedElementList != null) {
if (_lockedElementsList == null)
_lockedElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElements);
ConfigurationLockCollection localLockedElementList = ParseLockedAttributes(LockedElementList, ConfigurationLockCollectionType.LockedElements);
ConfigurationElementCollection collection = null;
if (props.DefaultCollectionProperty != null) // this is not a collection but it may contain a default collection
{
collection = this[props.DefaultCollectionProperty] as ConfigurationElementCollection;
if (collection != null && collection._lockedElementsList == null)
collection._lockedElementsList = _lockedElementsList;
}
foreach (string key in localLockedElementList) {
if (!_lockedElementsList.Contains(key)) {
_lockedElementsList.Add(key, ConfigurationValueFlags.Default); // add the local copy
ConfigurationProperty propToLock = Properties[key];
if (propToLock != null && typeof(ConfigurationElement).IsAssignableFrom(propToLock.Type)) {
((ConfigurationElement)this[key]).SetLocked();
}
if (key == LockAll) {
foreach (ConfigurationProperty prop in Properties) {
if (!string.IsNullOrEmpty(prop.Name) &&
prop.IsConfigurationElementType) {
((ConfigurationElement)this[prop]).SetLocked();
}
}
}
}
}
}
if (LockedAllElementsExceptList != null) {
ConfigurationLockCollection newCollection = ParseLockedAttributes(LockedAllElementsExceptList, ConfigurationLockCollectionType.LockedElementsExceptionList);
if (_lockedAllExceptElementsList == null) {
_lockedAllExceptElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElementsExceptionList, _elementTagName, newCollection);
_lockedAllExceptElementsList.ClearSeedList();
}
StringCollection intersectionCollection = IntersectLockCollections(_lockedAllExceptElementsList, newCollection);
ConfigurationElementCollection collection = null;
if (props.DefaultCollectionProperty != null) // this is not a collection but it may contain a default collection
{
collection = this[props.DefaultCollectionProperty] as ConfigurationElementCollection;
if (collection != null && collection._lockedAllExceptElementsList == null)
collection._lockedAllExceptElementsList = _lockedAllExceptElementsList;
}
_lockedAllExceptElementsList.ClearInternal(false);
foreach (string key in intersectionCollection) {
if (!_lockedAllExceptElementsList.Contains(key) || key == ElementTagName)
_lockedAllExceptElementsList.Add(key, ConfigurationValueFlags.Default); // add the local copy
}
foreach (ConfigurationProperty prop in Properties) {
if (!(string.IsNullOrEmpty(prop.Name) || _lockedAllExceptElementsList.Contains(prop.Name)) &&
prop.IsConfigurationElementType) {
((ConfigurationElement)this[prop]).SetLocked();
}
}
}
// Make sure default collections use the same lock element lists
if (defaultCollectionProperty != null) {
defaultCollection = (ConfigurationElement)this[defaultCollectionProperty];
if (_lockedElementsList == null) {
_lockedElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElements);
}
defaultCollection._lockedElementsList = _lockedElementsList;
if (_lockedAllExceptElementsList == null) {
_lockedAllExceptElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElementsExceptionList, reader.Name);
_lockedAllExceptElementsList.ClearSeedList();
}
defaultCollection._lockedAllExceptElementsList = _lockedAllExceptElementsList;
}
// This has to be the last thing to execute
PostDeserialize();
}
private object DeserializePropertyValue(ConfigurationProperty prop, XmlReader reader) {
Debug.Assert(prop != null, "prop != null");
Debug.Assert(reader != null, "reader != null");
// By default we try to load (i.e. parse/validate ) all properties
// If a property value is invalid ( cannot be parsed or is not valid ) we will keep the value
// as string ( from the xml ) and will write it out unchanged if needed
// If the property value is needed by users the actuall exception will be thrown
string xmlValue = reader.Value;
object propertyValue = null;
try {
propertyValue = prop.ConvertFromString(xmlValue);
// Validate the loaded and converted value
prop.Validate(propertyValue);
}
catch (ConfigurationException ce) {
// If the error is incomplete - complete it :)
if (string.IsNullOrEmpty(ce.Filename)) {
ce = new ConfigurationErrorsException(ce.Message, reader);
}
// Cannot parse/validate the value. Keep it as string
propertyValue = new InvalidPropValue(xmlValue, ce);
}
catch {
// If this is an exception related to the parsing/validating the
// value ConfigurationErrorsException should be thrown instead.
// If not - the exception is ok to surface out of here
Debug.Fail("Unknown exception type thrown");
}
return propertyValue;
}
internal static void ValidateElement(ConfigurationElement elem, ConfigurationValidatorBase propValidator, bool recursive) {
// Validate a config element with the per-type validator when a per-property ( propValidator ) is not supplied
// or with the per-prop validator when the element ( elem ) is a child property of another configuration element
ConfigurationValidatorBase validator = propValidator;
if ((validator == null) && // Not a property - use the per-type validator
(elem.ElementProperty != null)) {
validator = elem.ElementProperty.Validator;
// Since ElementProperty can be overriden by derived classes we need to make sure that
// the validator supports the type of elem every time
if ((validator != null) && !validator.CanValidate(elem.GetType())) {
throw new ConfigurationErrorsException(SR.GetString(SR.Validator_does_not_support_elem_type, elem.GetType().Name));
}
}
try {
if (validator != null) {
validator.Validate(elem);
}
}
catch (ConfigurationException) {
// ConfigurationElement validators are allowed to throw ConfigurationErrorsException.
throw;
}
catch (Exception ex) {
throw new ConfigurationErrorsException(SR.GetString(SR.Validator_element_not_valid, elem._elementTagName, ex.Message));
}
if (recursive == true) {
// Validate collection items:
// Note: this is a bit of a hack - we will exploit the fact that this method is called with recursive == true only when serializing the top level section
// At deserializtion time the per-element validator for collection items will get executed as part of their deserialization logic
// However we dont perform validation in the serialization logic ( because at that time the object is unmerged and not all data is present )
// so we have to do that validation here.
if (elem is ConfigurationElementCollection) {
if (elem is ConfigurationElementCollection) {
IEnumerator it = ((ConfigurationElementCollection)elem).GetElementsEnumerator();
while( it.MoveNext() ) {
ValidateElement((ConfigurationElement)it.Current, null, true);
}
}
}
// Validate all child elements recursively
for (int index = 0; index < elem.Values.Count; index++) {
ConfigurationElement value = elem.Values[index] as ConfigurationElement;
if (value != null) {
// Run the per-type validator on the child element and proceed with validation in subelements
// Note we dont run the per-property validator here since we run those when the property value is set
ValidateElement(value, null, true); // per-type
}
}
}
}
private void EnsureRequiredProperties(bool ensureKeysOnly) {
ConfigurationPropertyCollection props = Properties;
// Make sure all required properties are here
if (props != null) {
foreach (ConfigurationProperty prop in props) {
// The property is required but no value was found
if (prop.IsRequired && !_values.Contains(prop.Name)) {
// Required properties can be ommited when we need only the keys to be there
if (!ensureKeysOnly || prop.IsKey) {
_values[prop.Name] = OnRequiredPropertyNotFound(prop.Name);
}
}
}
}
}
protected virtual object OnRequiredPropertyNotFound(string name) {
// Derivied classes can override this to return a value for a required property that is missing
// Here we treat this as an error though
throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_required_attribute_missing, name),
PropertyFileName(name),
PropertyLineNumber(name));
}
protected virtual void PostDeserialize() {
// Please try to not add code in here
}
protected virtual void PreSerialize(XmlWriter writer) {
// Please try to not add code in here
}
protected virtual bool OnDeserializeUnrecognizedAttribute(String name, String value) {
return false;
}
protected virtual bool OnDeserializeUnrecognizedElement(String elementName, XmlReader reader) {
return false;
}
protected virtual string GetTransformedTypeString(string typeName)
{
if ( typeName == null || _configRecord == null || !_configRecord.TypeStringTransformerIsSet)
return typeName;
else
return _configRecord.TypeStringTransformer(typeName);
}
protected virtual string GetTransformedAssemblyString(string assemblyName)
{
if ( assemblyName == null || _configRecord == null || !_configRecord.AssemblyStringTransformerIsSet)
return assemblyName;
else
return _configRecord.AssemblyStringTransformer(assemblyName);
}
// Element
//
// Retrieve information specific to the element
//
public ElementInformation ElementInformation {
get {
if (_evaluationElement == null) {
_evaluationElement = new ElementInformation(this);
}
return _evaluationElement;
}
}
// EvaluationContext
//
// Retrieve information specific to the context of how we are
// being evaluated
//
protected ContextInformation EvaluationContext {
get {
if (_evalContext == null) {
if (_configRecord == null) {
// This is not associated with a context, so throw
// failure
throw new ConfigurationErrorsException(
SR.GetString(
SR.Config_element_no_context));
}
_evalContext = new ContextInformation(_configRecord);
}
return _evalContext;
}
}
internal protected virtual ConfigurationElementProperty ElementProperty {
get {
return _elementProperty;
}
}
internal ConfigurationLockCollection UnMergeLockList(
ConfigurationLockCollection sourceLockList,
ConfigurationLockCollection parentLockList,
ConfigurationSaveMode saveMode) {
if (sourceLockList.ExceptionList == false) {
switch (saveMode) {
case ConfigurationSaveMode.Modified: {
ConfigurationLockCollection tempLockList = new ConfigurationLockCollection(this, sourceLockList.LockType);
foreach (string lockedAttributeName in sourceLockList)
if (!parentLockList.Contains(lockedAttributeName) ||
sourceLockList.IsValueModified(lockedAttributeName)) {
tempLockList.Add(lockedAttributeName, ConfigurationValueFlags.Default);
}
return tempLockList;
}
case ConfigurationSaveMode.Minimal: {
ConfigurationLockCollection tempLockList = new ConfigurationLockCollection(this, sourceLockList.LockType);
foreach (string lockedAttributeName in sourceLockList)
if (!parentLockList.Contains(lockedAttributeName)) {
tempLockList.Add(lockedAttributeName, ConfigurationValueFlags.Default);
}
return tempLockList;
}
}
}
else {
// exception list write out the entire collection unless the entire collection
// came from the parent.
if (saveMode == ConfigurationSaveMode.Modified || saveMode == ConfigurationSaveMode.Minimal) {
bool sameAsParent = false;
if (sourceLockList.Count == parentLockList.Count) {
sameAsParent = true;
foreach (string lockedAttributeName in sourceLockList) {
if (!parentLockList.Contains(lockedAttributeName) ||
(sourceLockList.IsValueModified(lockedAttributeName) &&
saveMode == ConfigurationSaveMode.Modified)) {
sameAsParent = false;
}
}
}
if (sameAsParent == true) {
return null;
}
}
}
return sourceLockList;
}
//
// Return true if an attribute is one of our reserved locking attributes,
// false otherwise.
//
internal static bool IsLockAttributeName(string name) {
// optimize for common case that attribute name does not start with "lock"
if (!StringUtil.StartsWith(name, "lock")) {
return false;
}
foreach (string lockAttributeName in s_lockAttributeNames) {
if (name == lockAttributeName) {
return true;
}
}
return false;
}
protected bool HasContext {
get {
return _configRecord != null;
}
}
public Configuration CurrentConfiguration {
get {
return (_configRecord==null) ? null : _configRecord.CurrentConfiguration;
}
}
}
}
|