The Labs \ Source Viewer \ SSCLI \ System.Configuration \ ConfigurationElement

  1. //------------------------------------------------------------------------------
  2. // <copyright file="ConfigurationElement.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System;
  16. using System.Configuration.Internal;
  17. using System.Collections;
  18. using System.Collections.Specialized;
  19. using System.Collections.Generic;
  20. using System.IO;
  21. using System.Reflection;
  22. using System.Security.Permissions;
  23. using System.Xml;
  24. using System.Globalization;
  25. using System.ComponentModel;
  26. using System.Security;
  27. using System.Text;
  28. namespace System.Configuration
  29. {
  30.    
  31.     //
  32.     // Methods that are called by the configuration system, and must be overridable
  33.     // by derived classes that wish to implement their own serialization/deserialization
  34.     // IsModified()
  35.     // ResetModified()
  36.     // Reset(ConfigurationElement parentSection, object context)
  37.     // DeserializeSection(object context, XmlNode xmlNode)
  38.     // SerializeSection(ConfigurationElement parentSection, object context, string name)
  39.     //
  40.    
  41.     public abstract class ConfigurationElement
  42.     {
  43.         private const string LockAttributesKey = "lockAttributes";
  44.         private const string LockAllAttributesExceptKey = "lockAllAttributesExcept";
  45.         private const string LockElementsKey = "lockElements";
  46.         private const string LockAll = "*";
  47.         private const string LockAllElementsExceptKey = "lockAllElementsExcept";
  48.         private const string LockItemKey = "lockItem";
  49.         internal const string DefaultCollectionPropertyName = "";
  50.        
  51.         private static string[] s_lockAttributeNames = new string[] {LockAttributesKey, LockAllAttributesExceptKey, LockElementsKey, LockAllElementsExceptKey, LockItemKey};
  52.        
  53.         private static Hashtable s_propertyBags = new Hashtable();
  54.         private static Dictionary<Type, ConfigurationValidatorBase> s_perTypeValidators;
  55.         static internal readonly object s_nullPropertyValue = new object();
  56.         private static ConfigurationElementProperty s_ElementProperty = new ConfigurationElementProperty(new DefaultValidator());
  57.        
  58.         private bool _bDataToWrite;
  59.         private bool _bModified;
  60.         private bool _bReadOnly;
  61.         private bool _bElementPresent;
  62.         // Set to false if any part of the element is not inherited
  63.         private bool _bInited;
  64.         internal ConfigurationLockCollection _lockedAttributesList;
  65.         internal ConfigurationLockCollection _lockedAllExceptAttributesList;
  66.         internal ConfigurationLockCollection _lockedElementsList;
  67.         internal ConfigurationLockCollection _lockedAllExceptElementsList;
  68.         private ConfigurationValues _values;
  69.         private string _elementTagName;
  70.         private ElementInformation _evaluationElement;
  71.         private ConfigurationElementProperty _elementProperty = s_ElementProperty;
  72.         internal ConfigurationValueFlags _fItemLocked;
  73.         internal ContextInformation _evalContext;
  74.         internal BaseConfigurationRecord _configRecord;
  75.        
  76.         internal bool DataToWriteInternal {
  77.             get { return _bDataToWrite; }
  78.             set { _bDataToWrite = value; }
  79.         }
  80.        
  81.         static internal ConfigurationElement CreateElement(Type type)
  82.         {
  83.             ConfigurationElement element = (ConfigurationElement)TypeUtil.CreateInstanceWithReflectionPermission(type);
  84.             element.CallInit();
  85.             return element;
  86.         }
  87.        
  88.        
  89.         protected ConfigurationElement()
  90.         {
  91.             _values = new ConfigurationValues();
  92.            
  93.             // Set the per-type validator ( this will actually have an effect only for an attributed model elements )
  94.             // Note that in the case where the property bag fot this.GetType() has not yet been created
  95.             // the validator for this instance will get applied in ApplyValidatorsRecursive ( see this.get_Properties )
  96.             ApplyValidator(this);
  97.         }
  98.        
  99.         // Give elements that are added to a collection an opportunity to
  100.         //
  101.         protected internal virtual void Init()
  102.         {
  103.             // If Init is called by the derived class, we may be able
  104.             // to set _bInited to true if the derived class properly
  105.             // calls Init on its base.
  106.             _bInited = true;
  107.         }
  108.        
  109.         internal void CallInit()
  110.         {
  111.             // Ensure Init is called just once
  112.             if (!_bInited) {
  113.                 Init();
  114.                 _bInited = true;
  115.             }
  116.         }
  117.        
  118.         internal bool ElementPresent {
  119.             get { return _bElementPresent; }
  120.             set { _bElementPresent = value; }
  121.         }
  122.        
  123.         internal string ElementTagName {
  124.             get { return _elementTagName; }
  125.         }
  126.        
  127.         internal ConfigurationLockCollection LockedAttributesList {
  128.             get { return _lockedAttributesList; }
  129.         }
  130.        
  131.         internal ConfigurationLockCollection LockedAllExceptAttributesList {
  132.             get { return _lockedAllExceptAttributesList; }
  133.         }
  134.        
  135.         internal ConfigurationValueFlags ItemLocked {
  136.             get { return _fItemLocked; }
  137.         }
  138.        
  139.         public ConfigurationLockCollection LockAttributes {
  140.             get {
  141.                 if (_lockedAttributesList == null) {
  142.                     _lockedAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedAttributes);
  143.                 }
  144.                 return _lockedAttributesList;
  145.             }
  146.         }
  147.        
  148.         internal void MergeLocks(ConfigurationElement source)
  149.         {
  150.             if (source != null) {
  151.                 _fItemLocked = ((source._fItemLocked & ConfigurationValueFlags.Locked) != 0) ? (ConfigurationValueFlags.Inherited | source._fItemLocked) : _fItemLocked;
  152.                
  153.                 if (source._lockedAttributesList != null) {
  154.                     if (_lockedAttributesList == null) {
  155.                         _lockedAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedAttributes);
  156.                     }
  157.                     foreach (string key in source._lockedAttributesList)
  158.                         _lockedAttributesList.Add(key, ConfigurationValueFlags.Inherited);
  159.                     // Mark entry as from the parent - read only
  160.                 }
  161.                 if (source._lockedAllExceptAttributesList != null) {
  162.                     if (_lockedAllExceptAttributesList == null) {
  163.                         _lockedAllExceptAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedExceptionList, String.Empty, source._lockedAllExceptAttributesList);
  164.                     }
  165.                    
  166.                     StringCollection intersectionCollection = IntersectLockCollections(_lockedAllExceptAttributesList, source._lockedAllExceptAttributesList);
  167.                    
  168.                     _lockedAllExceptAttributesList.ClearInternal(false);
  169.                     foreach (string key in intersectionCollection) {
  170.                         _lockedAllExceptAttributesList.Add(key, ConfigurationValueFlags.Default);
  171.                     }
  172.                    
  173.                 }
  174.                 if (source._lockedElementsList != null) {
  175.                     if (_lockedElementsList == null) {
  176.                         _lockedElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElements);
  177.                     }
  178.                    
  179.                     ConfigurationElementCollection collection = null;
  180.                     // this is not a collection but it may contain a default collection
  181.                     if (Properties.DefaultCollectionProperty != null) {
  182.                         collection = this[Properties.DefaultCollectionProperty] as ConfigurationElementCollection;
  183.                         if (collection != null) {
  184.                             collection.internalElementTagName = source.ElementTagName;
  185.                             // Default collections don't know there tag name
  186.                             if (collection._lockedElementsList == null) {
  187.                                 collection._lockedElementsList = _lockedElementsList;
  188.                                 //point to the same instance of the collection from parent
  189.                             }
  190.                         }
  191.                     }
  192.                    
  193.                     foreach (string key in source._lockedElementsList) {
  194.                         _lockedElementsList.Add(key, ConfigurationValueFlags.Inherited);
  195.                         // Mark entry as from the parent - read only
  196.                         if (collection != null) {
  197.                             collection._lockedElementsList.Add(key, ConfigurationValueFlags.Inherited);
  198.                             // add the local copy
  199.                         }
  200.                     }
  201.                 }
  202.                
  203.                 if (source._lockedAllExceptElementsList != null) {
  204.                     if (_lockedAllExceptElementsList == null || _lockedAllExceptElementsList.Count == 0) {
  205.                         _lockedAllExceptElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElementsExceptionList, source._elementTagName, source._lockedAllExceptElementsList);
  206.                     }
  207.                     StringCollection intersectionCollection = IntersectLockCollections(_lockedAllExceptElementsList, source._lockedAllExceptElementsList);
  208.                    
  209.                     ConfigurationElementCollection collection = null;
  210.                     if (Properties.DefaultCollectionProperty != null) {
  211.                         // this is not a collection but it may contain a default collection
  212.                         collection = this[Properties.DefaultCollectionProperty] as ConfigurationElementCollection;
  213.                         if (collection != null && collection._lockedAllExceptElementsList == null) {
  214.                             // point default collection to the parent collection
  215.                             collection._lockedAllExceptElementsList = _lockedAllExceptElementsList;
  216.                         }
  217.                     }
  218.                     _lockedAllExceptElementsList.ClearInternal(false);
  219.                     foreach (string key in intersectionCollection) {
  220.                         if (!_lockedAllExceptElementsList.Contains(key) || key == ElementTagName)
  221.                             _lockedAllExceptElementsList.Add(key, ConfigurationValueFlags.Default);
  222.                         // add the local copy
  223.                     }
  224.                     if (_lockedAllExceptElementsList.HasParentElements) {
  225.                         foreach (ConfigurationProperty prop in Properties) {
  226.                             if ((!_lockedAllExceptElementsList.Contains(prop.Name)) && typeof(ConfigurationElement).IsAssignableFrom(prop.Type)) {
  227.                                 ((ConfigurationElement)this[prop]).SetLocked();
  228.                             }
  229.                         }
  230.                     }
  231.                 }
  232.             }
  233.         }
  234.        
  235.         internal void HandleLockedAttributes(ConfigurationElement source)
  236.         {
  237.             // if there are locked attributes on this collection element
  238.             if (source != null) {
  239.                 if (source._lockedAttributesList != null || source._lockedAllExceptAttributesList != null) {
  240.                     // enumerate the possible locked properties
  241.                     foreach (PropertyInformation propInfo in source.ElementInformation.Properties) {
  242.                         if ((source._lockedAttributesList != null && (source._lockedAttributesList.Contains(propInfo.Name) || source._lockedAttributesList.Contains(LockAll))) || (source._lockedAllExceptAttributesList != null && !source._lockedAllExceptAttributesList.Contains(propInfo.Name))) {
  243.                             // if the attribute has been locked in the source then check to see
  244.                             // if the local config is trying to override it
  245.                             if (propInfo.Name != LockAttributesKey && propInfo.Name != LockAllAttributesExceptKey) {
  246.                                
  247.                                 if (ElementInformation.Properties[propInfo.Name] == null) {
  248.                                     // locked items are not defined
  249.                                     ConfigurationPropertyCollection props = Properties;
  250.                                     // so create the property based in the source item
  251.                                     ConfigurationProperty prop = (ConfigurationProperty)source.Properties[propInfo.Name];
  252.                                     props.Add(prop);
  253.                                     // Add the property information to the property bag
  254.                                     _evaluationElement = null;
  255.                                     // flush the cached element data
  256.                                     // Add the data from the source element but mark it as in herited
  257.                                     // This must use setvalue in order to set the lock and inherited flags
  258.                                     ConfigurationValueFlags flags = ConfigurationValueFlags.Inherited | ConfigurationValueFlags.Locked;
  259.                                     _values.SetValue(propInfo.Name, propInfo.Value, flags, source.PropertyInfoInternal(propInfo.Name));
  260.                                    
  261.                                 }
  262.                                 else {
  263.                                     // don't error when optional attibute are not defined yet
  264.                                     if (ElementInformation.Properties[propInfo.Name].ValueOrigin == PropertyValueOrigin.SetHere) {
  265.                                         // Don't allow the override
  266.                                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, propInfo.Name));
  267.                                     }
  268.                                     // They did not override so we need to make sure the value comes from the locked one
  269.                                     ElementInformation.Properties[propInfo.Name].Value = propInfo.Value;
  270.                                 }
  271.                             }
  272.                         }
  273.                     }
  274.                 }
  275.             }
  276.         }
  277.        
  278.         // AssociateContext
  279.         //
  280.         // Associate a context with this element
  281.         //
  282.         internal virtual void AssociateContext(BaseConfigurationRecord configRecord)
  283.         {
  284.             _configRecord = configRecord;
  285.             Values.AssociateContext(configRecord);
  286.         }
  287.        
  288.         public ConfigurationLockCollection LockAllAttributesExcept {
  289. /*protected internal virtual*/            get {
  290.                 if (_lockedAllExceptAttributesList == null) {
  291.                     _lockedAllExceptAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedExceptionList, _elementTagName);
  292.                 }
  293.                 return _lockedAllExceptAttributesList;
  294.             }
  295.         }
  296.        
  297.         public ConfigurationLockCollection LockElements {
  298.             get {
  299.                 if (_lockedElementsList == null) {
  300.                     _lockedElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElements);
  301.                 }
  302.                 return _lockedElementsList;
  303.             }
  304.         }
  305.        
  306.         public ConfigurationLockCollection LockAllElementsExcept {
  307.             get {
  308.                 if (_lockedAllExceptElementsList == null) {
  309.                     _lockedAllExceptElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElementsExceptionList, _elementTagName);
  310.                 }
  311.                 return _lockedAllExceptElementsList;
  312.             }
  313.         }
  314.        
  315.         public bool LockItem {
  316.             get { return ((_fItemLocked & ConfigurationValueFlags.Locked) != 0); }
  317.             set {
  318.                 if ((_fItemLocked & ConfigurationValueFlags.Inherited) == 0) {
  319.                     _fItemLocked = (value == true) ? ConfigurationValueFlags.Locked : ConfigurationValueFlags.Default;
  320.                     _fItemLocked |= ConfigurationValueFlags.Modified;
  321.                 }
  322.                 else {
  323.                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, LockItemKey));
  324.                 }
  325.             }
  326.         }
  327.        
  328.         protected internal virtual bool IsModified()
  329.         {
  330.            
  331.             if (_bModified) {
  332.                 return true;
  333.             }
  334.            
  335.             if (_lockedAttributesList != null && _lockedAttributesList.IsModified) {
  336.                 return true;
  337.             }
  338.            
  339.             if (_lockedAllExceptAttributesList != null && _lockedAllExceptAttributesList.IsModified) {
  340.                 return true;
  341.             }
  342.            
  343.             if (_lockedElementsList != null && _lockedElementsList.IsModified) {
  344.                 return true;
  345.             }
  346.            
  347.             if (_lockedAllExceptElementsList != null && _lockedAllExceptElementsList.IsModified) {
  348.                 return true;
  349.             }
  350.            
  351.             if ((_fItemLocked & ConfigurationValueFlags.Modified) != 0) {
  352.                 return true;
  353.             }
  354.            
  355.             foreach (ConfigurationElement elem in _values.ConfigurationElements) {
  356.                 if (elem.IsModified()) {
  357.                     return true;
  358.                 }
  359.             }
  360.             return false;
  361.         }
  362.        
  363.         protected internal virtual void ResetModified()
  364.         {
  365.             _bModified = false;
  366.            
  367.             if (_lockedAttributesList != null) {
  368.                 _lockedAttributesList.ResetModified();
  369.             }
  370.            
  371.             if (_lockedAllExceptAttributesList != null) {
  372.                 _lockedAllExceptAttributesList.ResetModified();
  373.             }
  374.            
  375.             if (_lockedElementsList != null) {
  376.                 _lockedElementsList.ResetModified();
  377.             }
  378.            
  379.             if (_lockedAllExceptElementsList != null) {
  380.                 _lockedAllExceptElementsList.ResetModified();
  381.             }
  382.            
  383.             foreach (ConfigurationElement elem in _values.ConfigurationElements) {
  384.                 elem.ResetModified();
  385.             }
  386.         }
  387.        
  388.         public virtual bool IsReadOnly()
  389.         {
  390.             return _bReadOnly;
  391.         }
  392.        
  393.         protected internal virtual void SetReadOnly()
  394.         {
  395.             _bReadOnly = true;
  396.             foreach (ConfigurationElement elem in _values.ConfigurationElements) {
  397.                 elem.SetReadOnly();
  398.             }
  399.         }
  400.        
  401.         internal void SetLocked()
  402.         {
  403.             _fItemLocked = ConfigurationValueFlags.Locked | ConfigurationValueFlags.XMLParentInherited;
  404.            
  405.             foreach (ConfigurationProperty prop in Properties) {
  406.                 ConfigurationElement elem = this[prop] as ConfigurationElement;
  407.                 if (elem != null) {
  408.                     if (elem.GetType() != this.GetType()) {
  409.                         elem.SetLocked();
  410.                     }
  411.                    
  412.                     ConfigurationElementCollection collection = this[prop] as ConfigurationElementCollection;
  413.                     if (collection != null) {
  414.                         foreach (object obj in collection) {
  415.                             ConfigurationElement element = obj as ConfigurationElement;
  416.                             if (element != null) {
  417.                                 element.SetLocked();
  418.                             }
  419.                         }
  420.                     }
  421.                 }
  422.             }
  423.         }
  424.        
  425.         // GetErrorsList
  426.         //
  427.         // Get the list of Errors for this location and all
  428.         // sub locations
  429.         //
  430.         internal ArrayList GetErrorsList()
  431.         {
  432.             ArrayList errorList = new ArrayList();
  433.            
  434.             ListErrors(errorList);
  435.            
  436.             return errorList;
  437.         }
  438.        
  439.         // GetErrors
  440.         //
  441.         // Get a ConfigurationErrorsException that contains the errors
  442.         // for this ConfigurationElement and its children
  443.         //
  444.         internal ConfigurationErrorsException GetErrors()
  445.         {
  446.             ArrayList errorsList;
  447.            
  448.             errorsList = GetErrorsList();
  449.            
  450.             if (errorsList.Count == 0) {
  451.                 return null;
  452.             }
  453.            
  454.             ConfigurationErrorsException e = new ConfigurationErrorsException(errorsList);
  455.             return e;
  456.         }
  457.        
  458.         protected virtual void ListErrors(IList errorList)
  459.         {
  460.             // First list errors in this element, then in subelements
  461.             foreach (InvalidPropValue invalidValue in _values.InvalidValues) {
  462.                 errorList.Add(invalidValue.Error);
  463.             }
  464.            
  465.             foreach (ConfigurationElement elem in _values.ConfigurationElements) {
  466.                 elem.ListErrors(errorList);
  467.                 ConfigurationElementCollection collection = elem as ConfigurationElementCollection;
  468.                 if (collection != null) {
  469.                     foreach (ConfigurationElement item in collection) {
  470.                         item.ListErrors(errorList);
  471.                     }
  472.                 }
  473.             }
  474.         }
  475.        
  476.         protected internal virtual void InitializeDefault()
  477.         {
  478.         }
  479.        
  480.         internal void CheckLockedElement(string elementName, XmlReader reader)
  481.         {
  482.             // have to check if clear was locked!
  483.             if (elementName != null) {
  484.                 if (((_lockedElementsList != null) && (_lockedElementsList.DefinedInParent(LockAll) || _lockedElementsList.DefinedInParent(elementName))) || ((_lockedAllExceptElementsList != null && _lockedAllExceptElementsList.Count != 0) && _lockedAllExceptElementsList.HasParentElements && !_lockedAllExceptElementsList.DefinedInParent(elementName) || (_fItemLocked & ConfigurationValueFlags.Inherited) != 0)) {
  485.                    
  486.                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_element_locked, elementName), reader);
  487.                 }
  488.             }
  489.         }
  490.        
  491.         internal void RemoveAllInheritedLocks()
  492.         {
  493.             if (_lockedAttributesList != null) {
  494.                 _lockedAttributesList.RemoveInheritedLocks();
  495.             }
  496.             if (_lockedElementsList != null) {
  497.                 _lockedElementsList.RemoveInheritedLocks();
  498.             }
  499.             if (_lockedAllExceptAttributesList != null) {
  500.                 _lockedAllExceptAttributesList.RemoveInheritedLocks();
  501.             }
  502.             if (_lockedAllExceptElementsList != null) {
  503.                 _lockedAllExceptElementsList.RemoveInheritedLocks();
  504.             }
  505.         }
  506.        
  507.         internal void ResetLockLists(ConfigurationElement parentElement)
  508.         {
  509.             _lockedAttributesList = null;
  510.             _lockedAllExceptAttributesList = null;
  511.             _lockedElementsList = null;
  512.             _lockedAllExceptElementsList = null;
  513.            
  514.             if (parentElement != null) {
  515.                 _fItemLocked = ((parentElement._fItemLocked & ConfigurationValueFlags.Locked) != 0) ? (ConfigurationValueFlags.Inherited | parentElement._fItemLocked) : ConfigurationValueFlags.Default;
  516.                
  517.                 if (parentElement._lockedAttributesList != null) {
  518.                     _lockedAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedAttributes);
  519.                     foreach (string key in parentElement._lockedAttributesList)
  520.                         _lockedAttributesList.Add(key, ConfigurationValueFlags.Inherited);
  521.                     // Mark entry as from the parent - read only
  522.                 }
  523.                 if (parentElement._lockedAllExceptAttributesList != null) {
  524.                     _lockedAllExceptAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedExceptionList, String.Empty, parentElement._lockedAllExceptAttributesList);
  525.                 }
  526.                 if (parentElement._lockedElementsList != null) {
  527.                     _lockedElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElements);
  528.                    
  529.                     ConfigurationElementCollection collection = null;
  530.                     // this is not a collection but it may contain a default collection
  531.                     if (Properties.DefaultCollectionProperty != null) {
  532.                         collection = this[Properties.DefaultCollectionProperty] as ConfigurationElementCollection;
  533.                         if (collection != null) {
  534.                             collection.internalElementTagName = parentElement.ElementTagName;
  535.                             // Default collections don't know there tag name
  536.                             if (collection._lockedElementsList == null) {
  537.                                 collection._lockedElementsList = _lockedElementsList;
  538.                             }
  539.                         }
  540.                     }
  541.                    
  542.                     foreach (string key in parentElement._lockedElementsList) {
  543.                         _lockedElementsList.Add(key, ConfigurationValueFlags.Inherited);
  544.                         // Mark entry as from the parent - read only
  545.                     }
  546.                 }
  547.                
  548.                 if (parentElement._lockedAllExceptElementsList != null) {
  549.                     _lockedAllExceptElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElementsExceptionList, parentElement._elementTagName, parentElement._lockedAllExceptElementsList);
  550.                    
  551.                     ConfigurationElementCollection collection = null;
  552.                     // this is not a collection but it may contain a default collection
  553.                     if (Properties.DefaultCollectionProperty != null) {
  554.                         collection = this[Properties.DefaultCollectionProperty] as ConfigurationElementCollection;
  555.                         if (collection != null && collection._lockedAllExceptElementsList == null) {
  556.                             collection._lockedAllExceptElementsList = _lockedAllExceptElementsList;
  557.                         }
  558.                     }
  559.                 }
  560.             }
  561.         }
  562.        
  563.         protected internal virtual void Reset(ConfigurationElement parentElement)
  564.         {
  565.             Values.Clear();
  566.             ResetLockLists(parentElement);
  567.             ConfigurationPropertyCollection props = Properties;
  568.             // Force the bag to be up to date
  569.             _bElementPresent = false;
  570.             if (parentElement == null) {
  571.                 InitializeDefault();
  572.             }
  573.             else {
  574.                 bool hasAnyChildElements = false;
  575.                
  576.                 ConfigurationPropertyCollection collectionKeys = null;
  577.                
  578.                 for (int index = 0; index < parentElement.Values.Count; index++) {
  579.                     string key = parentElement.Values.GetKey(index);
  580.                     ConfigurationValue ConfigValue = parentElement.Values.GetConfigValue(index);
  581.                     object value = (ConfigValue != null) ? ConfigValue.Value : null;
  582.                     PropertySourceInfo sourceInfo = (ConfigValue != null) ? ConfigValue.SourceInfo : null;
  583.                    
  584.                     ConfigurationProperty prop = (ConfigurationProperty)parentElement.Properties[key];
  585.                     if (prop == null || ((collectionKeys != null) && !collectionKeys.Contains(prop.Name))) {
  586.                         continue;
  587.                     }
  588.                    
  589.                     if (typeof(ConfigurationElement).IsAssignableFrom(prop.Type)) {
  590.                         hasAnyChildElements = true;
  591.                     }
  592.                     else {
  593.                         ConfigurationValueFlags flags = ConfigurationValueFlags.Inherited | (((_lockedAttributesList != null) && (_lockedAttributesList.Contains(key) || _lockedAttributesList.Contains(LockAll)) || (_lockedAllExceptAttributesList != null) && !_lockedAllExceptAttributesList.Contains(key)) ? ConfigurationValueFlags.Locked : ConfigurationValueFlags.Default);
  594.                        
  595.                         if (value != s_nullPropertyValue) {
  596.                             // _values[key] = value;
  597.                             _values.SetValue(key, value, flags, sourceInfo);
  598.                         }
  599.                         // this is for optional provider models keys
  600.                         if (!props.Contains(key)) {
  601.                             props.Add(prop);
  602.                             _values.SetValue(key, value, flags, sourceInfo);
  603.                         }
  604.                     }
  605.                 }
  606.                
  607.                 if (hasAnyChildElements) {
  608.                     for (int index = 0; index < parentElement.Values.Count; index++) {
  609.                         string key = parentElement.Values.GetKey(index);
  610.                         object value = parentElement.Values[index];
  611.                        
  612.                         ConfigurationProperty prop = (ConfigurationProperty)parentElement.Properties[key];
  613.                         if ((prop != null) && typeof(ConfigurationElement).IsAssignableFrom(prop.Type)) {
  614.                             //((ConfigurationElement)value).SerializeToXmlElement(writer, prop.Name);
  615.                             ConfigurationElement childElement = (ConfigurationElement)this[prop];
  616.                             childElement.Reset((ConfigurationElement)value);
  617.                         }
  618.                     }
  619.                 }
  620.             }
  621.         }
  622.        
  623.         public override bool Equals(object compareTo)
  624.         {
  625.             ConfigurationElement compareToElem = compareTo as ConfigurationElement;
  626.            
  627.             if (compareToElem == null || (compareTo.GetType() != this.GetType()) || ((compareToElem != null) && (compareToElem.Properties.Count != this.Properties.Count))) {
  628.                 return false;
  629.             }
  630.            
  631.             foreach (ConfigurationProperty configProperty in this.Properties) {
  632.                
  633.                 if (!Object.Equals(Values[configProperty.Name], compareToElem.Values[configProperty.Name])) {
  634.                     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))))
  635.                         return false;
  636.                 }
  637.             }
  638.             return true;
  639.         }
  640.        
  641.         public override int GetHashCode()
  642.         {
  643.             int hHashCode = 0;
  644.             foreach (ConfigurationProperty configProperty in this.Properties) {
  645.                 object o = this[configProperty];
  646.                 if (o != null) {
  647.                     hHashCode ^= this[configProperty].GetHashCode();
  648.                 }
  649.             }
  650.             return hHashCode;
  651.         }
  652.        
  653.         protected internal object this[ConfigurationProperty prop]
  654.         {
  655.             get {
  656.                 object o = _values[prop.Name];
  657.                 if (o == null) {
  658.                     lock (_values.SyncRoot) {
  659.                         o = _values[prop.Name];
  660.                         if (o == null) {
  661.                             if (typeof(ConfigurationElement).IsAssignableFrom(prop.Type)) {
  662.                                 ConfigurationElement childElement = CreateElement(prop.Type);
  663.                                
  664.                                 if (_bReadOnly) {
  665.                                     childElement.SetReadOnly();
  666.                                 }
  667.                                
  668.                                 if (typeof(ConfigurationElementCollection).IsAssignableFrom(prop.Type)) {
  669.                                     ConfigurationElementCollection childElementCollection = childElement as ConfigurationElementCollection;
  670.                                     if (prop.AddElementName != null)
  671.                                         childElementCollection.AddElementName = prop.AddElementName;
  672.                                     if (prop.RemoveElementName != null)
  673.                                         childElementCollection.RemoveElementName = prop.RemoveElementName;
  674.                                     if (prop.ClearElementName != null)
  675.                                         childElementCollection.ClearElementName = prop.ClearElementName;
  676.                                 }
  677.                                
  678.                                 //_values[prop.Name] = childElement;
  679.                                 _values.SetValue(prop.Name, childElement, ConfigurationValueFlags.Inherited, null);
  680.                                 o = childElement;
  681.                             }
  682.                             else {
  683.                                 o = prop.DefaultValue;
  684.                             }
  685.                         }
  686.                     }
  687.                 }
  688.                 else if (o == s_nullPropertyValue) {
  689.                     o = null;
  690.                 }
  691.                
  692.                 // If its an invalid value - throw the error now
  693.                 if (o is InvalidPropValue) {
  694.                     throw ((InvalidPropValue)o).Error;
  695.                 }
  696.                
  697.                 return o;
  698.             }
  699.            
  700.                 // Do not ignore locks!!!
  701.             set { SetPropertyValue(prop, value, false); }
  702.         }
  703.        
  704.         protected internal object this[string propertyName]
  705.         {
  706.             get {
  707.                 ConfigurationProperty prop = Properties[propertyName];
  708.                 if (prop == null) {
  709.                     prop = Properties[DefaultCollectionPropertyName];
  710.                     if (prop.ProvidedName != propertyName) {
  711.                         return null;
  712.                     }
  713.                 }
  714.                 return this[prop];
  715.             }
  716.             set {
  717.                 Debug.Assert(Properties.Contains(propertyName), "Properties.Contains(propertyName)");
  718.                 SetPropertyValue(Properties[propertyName], value, false);
  719.                 // Do not ignore locks!!!
  720.             }
  721.         }
  722.        
  723.         private static void ApplyInstanceAttributes(object instance)
  724.         {
  725.            
  726.             Debug.Assert(instance is ConfigurationElement, "instance is ConfigurationElement");
  727.             Type type = instance.GetType();
  728.            
  729.             foreach (PropertyInfo propertyInformation in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
  730.                
  731.                 ConfigurationPropertyAttribute attribProperty = Attribute.GetCustomAttribute(propertyInformation, typeof(ConfigurationPropertyAttribute)) as ConfigurationPropertyAttribute;
  732.                
  733.                 if (attribProperty != null) {
  734.                     Type propertyType = propertyInformation.PropertyType;
  735.                     // Collections need some customization when the collection attribute is present
  736.                     if (typeof(ConfigurationElementCollection).IsAssignableFrom(propertyType)) {
  737.                         ConfigurationCollectionAttribute attribCollection = Attribute.GetCustomAttribute(propertyInformation, typeof(ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute;
  738.                        
  739.                         // If none on the property - see if there is an attribute on the collection type itself
  740.                         if (attribCollection == null) {
  741.                             attribCollection = Attribute.GetCustomAttribute(propertyType, typeof(ConfigurationCollectionAttribute)) as ConfigurationCollectionAttribute;
  742.                         }
  743.                        
  744.                         ConfigurationElementCollection coll = propertyInformation.GetValue(instance, null) as ConfigurationElementCollection;
  745.                         if (coll == null) {
  746.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_element_null_instance, propertyInformation.Name, attribProperty.Name));
  747.                         }
  748.                        
  749.                         // If the attribute is found - get the collection instance and set the data from the attribute
  750.                         if (attribCollection != null) {
  751.                             if (attribCollection.AddItemName.IndexOf(',') == -1) {
  752.                                 coll.AddElementName = attribCollection.AddItemName;
  753.                             }
  754.                            
  755.                             coll.RemoveElementName = attribCollection.RemoveItemName;
  756.                            
  757.                             coll.ClearElementName = attribCollection.ClearItemsName;
  758.                         }
  759.                     }
  760.                     else if (typeof(ConfigurationElement).IsAssignableFrom(propertyType)) {
  761.                         // Nested configuration element - handle recursively
  762.                         object element = propertyInformation.GetValue(instance, null);
  763.                         if (element == null) {
  764.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_element_null_instance, propertyInformation.Name, attribProperty.Name));
  765.                         }
  766.                        
  767.                         ApplyInstanceAttributes(element);
  768.                     }
  769.                 }
  770.             }
  771.         }
  772.        
  773.         private static bool PropertiesFromType(Type type, out ConfigurationPropertyCollection result)
  774.         {
  775.             ConfigurationPropertyCollection properties = (ConfigurationPropertyCollection)s_propertyBags[type];
  776.             result = null;
  777.             bool firstTimeInit = false;
  778.             if (properties == null) {
  779.                 lock (s_propertyBags.SyncRoot) {
  780.                     properties = (ConfigurationPropertyCollection)s_propertyBags[type];
  781.                     if (properties == null) {
  782.                         properties = CreatePropertyBagFromType(type);
  783.                         s_propertyBags[type] = properties;
  784.                         firstTimeInit = true;
  785.                     }
  786.                 }
  787.             }
  788.             result = properties;
  789.             return firstTimeInit;
  790.         }
  791.        
  792.         private static ConfigurationPropertyCollection CreatePropertyBagFromType(Type type)
  793.         {
  794.             Debug.Assert(type != null, "type != null");
  795.            
  796.             // For ConfigurationElement derived classes - get the per-type validator
  797.             if (typeof(ConfigurationElement).IsAssignableFrom(type)) {
  798.                 ConfigurationValidatorAttribute attribValidator = Attribute.GetCustomAttribute(type, typeof(ConfigurationValidatorAttribute)) as ConfigurationValidatorAttribute;
  799.                
  800.                 if (attribValidator != null) {
  801.                     ConfigurationValidatorBase validator = attribValidator.ValidatorInstance;
  802.                    
  803.                     if (validator != null) {
  804.                         CachePerTypeValidator(type, validator);
  805.                     }
  806.                 }
  807.             }
  808.            
  809.             ConfigurationPropertyCollection properties = new ConfigurationPropertyCollection();
  810.            
  811.             foreach (PropertyInfo propertyInformation in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
  812.                 ConfigurationProperty newProp = CreateConfigurationPropertyFromAttributes(propertyInformation);
  813.                
  814.                 if (newProp != null) {
  815.                     properties.Add(newProp);
  816.                 }
  817.             }
  818.            
  819.             return properties;
  820.         }
  821.         private static ConfigurationProperty CreateConfigurationPropertyFromAttributes(PropertyInfo propertyInformation)
  822.         {
  823.             Debug.Assert(propertyInformation != null, "propertyInformation != null");
  824.            
  825.             ConfigurationProperty result = null;
  826.            
  827.             ConfigurationPropertyAttribute attribProperty = Attribute.GetCustomAttribute(propertyInformation, typeof(ConfigurationPropertyAttribute)) as ConfigurationPropertyAttribute;
  828.            
  829.             // If there is no ConfigurationProperty attrib - this is not considered a property
  830.             if (attribProperty != null) {
  831.                 result = new ConfigurationProperty(propertyInformation);
  832.             }
  833.            
  834.             // Handle some special cases of property types
  835.             if (result != null && typeof(ConfigurationElement).IsAssignableFrom(result.Type)) {
  836.                 ConfigurationPropertyCollection unused = null;
  837.                
  838.                 PropertiesFromType(result.Type, out unused);
  839.             }
  840.            
  841.             return result;
  842.         }
  843.        
  844.         private static void CachePerTypeValidator(Type type, ConfigurationValidatorBase validator)
  845.         {
  846.             Debug.Assert((type != null) && (validator != null));
  847.             Debug.Assert(typeof(ConfigurationElement).IsAssignableFrom(type));
  848.            
  849.             // Use the same lock as the property bag lock since in the current implementation
  850.             // the only way to get to this method is through the code path that locks the property bag cache first ( see PropertiesFromType() )
  851.            
  852.             // NOTE[ Thread Safety ]: Non-guarded access to static variable - since this code is called only from CreatePropertyBagFromType
  853.             // 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
  854.             if (s_perTypeValidators == null) {
  855.                 s_perTypeValidators = new Dictionary<Type, ConfigurationValidatorBase>();
  856.             }
  857.            
  858.             // A type validator should be cached only once. If it isn't then attribute parsing is done more then once which should be avoided
  859.             Debug.Assert(!s_perTypeValidators.ContainsKey(type));
  860.            
  861.             // Make sure the supplied validator supports validating this object
  862.             if (!validator.CanValidate(type)) {
  863.                 throw new ConfigurationErrorsException(SR.GetString(SR.Validator_does_not_support_elem_type, type.Name));
  864.             }
  865.            
  866.             s_perTypeValidators.Add(type, validator);
  867.         }
  868.        
  869.         private static void ApplyValidatorsRecursive(ConfigurationElement root)
  870.         {
  871.             Debug.Assert(root != null);
  872.            
  873.             // Apply the validator on 'root'
  874.             ApplyValidator(root);
  875.            
  876.             // Apply validators on child elements ( note - we will do this only on already created child elements
  877.             // The non created ones will get their validators in the ctor
  878.             foreach (ConfigurationElement elem in root._values.ConfigurationElements) {
  879.                
  880.                 ApplyValidatorsRecursive(elem);
  881.             }
  882.         }
  883.        
  884.         private static void ApplyValidator(ConfigurationElement elem)
  885.         {
  886.             Debug.Assert(elem != null);
  887.            
  888.             if ((s_perTypeValidators != null) && (s_perTypeValidators.ContainsKey(elem.GetType()))) {
  889.                 elem._elementProperty = new ConfigurationElementProperty(s_perTypeValidators[elem.GetType()]);
  890.             }
  891.         }
  892.        
  893.         protected void SetPropertyValue(ConfigurationProperty prop, object value, bool ignoreLocks)
  894.         {
  895.             if (IsReadOnly()) {
  896.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_read_only));
  897.             }
  898.            
  899.             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)) {
  900.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, prop.Name));
  901.             }
  902.            
  903.             _bModified = true;
  904.            
  905.             // Run the new value through the validator to make sure its ok to store it
  906.             if (value != null) {
  907.                 prop.Validate(value);
  908.             }
  909.            
  910.             _values[prop.Name] = (value != null) ? value : s_nullPropertyValue;
  911.         }
  912.        
  913.         protected internal virtual ConfigurationPropertyCollection Properties {
  914.             get {
  915.                 ConfigurationPropertyCollection result = null;
  916.                
  917.                 if (PropertiesFromType(this.GetType(), out result)) {
  918.                     ApplyInstanceAttributes(this);
  919.                     ApplyValidatorsRecursive(this);
  920.                 }
  921.                 return result;
  922.             }
  923.         }
  924.        
  925.         internal ConfigurationValues Values {
  926.             get { return _values; }
  927.         }
  928.        
  929.         internal PropertySourceInfo PropertyInfoInternal(string propertyName)
  930.         {
  931.             return (PropertySourceInfo)_values.GetSourceInfo(propertyName);
  932.         }
  933.        
  934.         internal string PropertyFileName(string propertyName)
  935.         {
  936.             PropertySourceInfo p = (PropertySourceInfo)PropertyInfoInternal(propertyName);
  937.             if (p == null)
  938.                 p = (PropertySourceInfo)PropertyInfoInternal(String.Empty);
  939.             // Get the filename of the parent if prop is not there
  940.             if (p == null)
  941.                 return String.Empty;
  942.             return p.FileName;
  943.         }
  944.        
  945.         internal int PropertyLineNumber(string propertyName)
  946.         {
  947.             PropertySourceInfo p = (PropertySourceInfo)PropertyInfoInternal(propertyName);
  948.             if (p == null)
  949.                 p = (PropertySourceInfo)PropertyInfoInternal(String.Empty);
  950.             if (p == null)
  951.                 return 0;
  952.             return p.LineNumber;
  953.         }
  954.        
  955.         internal virtual void Dump(TextWriter tw)
  956.         {
  957.             tw.WriteLine("Type: " + GetType().FullName);
  958.            
  959.             foreach (PropertyInfo pi in GetType().GetProperties()) {
  960.                 tw.WriteLine("{0}: {1}", pi.Name, pi.GetValue(this, null));
  961.             }
  962.            
  963.         }
  964.        
  965.         protected internal virtual void Unmerge(ConfigurationElement sourceElement, ConfigurationElement parentElement, ConfigurationSaveMode saveMode)
  966.         {
  967.             if (sourceElement != null) {
  968.                 bool hasAnyChildElements = false;
  969.                
  970.                
  971.                 _lockedAllExceptAttributesList = sourceElement._lockedAllExceptAttributesList;
  972.                 _lockedAllExceptElementsList = sourceElement._lockedAllExceptElementsList;
  973.                 _fItemLocked = sourceElement._fItemLocked;
  974.                 _lockedAttributesList = sourceElement._lockedAttributesList;
  975.                 _lockedElementsList = sourceElement._lockedElementsList;
  976.                 AssociateContext(sourceElement._configRecord);
  977.                
  978.                 if (parentElement != null) {
  979.                     if (parentElement._lockedAttributesList != null)
  980.                         _lockedAttributesList = UnMergeLockList(sourceElement._lockedAttributesList, parentElement._lockedAttributesList, saveMode);
  981.                     if (parentElement._lockedElementsList != null)
  982.                         _lockedElementsList = UnMergeLockList(sourceElement._lockedElementsList, parentElement._lockedElementsList, saveMode);
  983.                     if (parentElement._lockedAllExceptAttributesList != null)
  984.                         _lockedAllExceptAttributesList = UnMergeLockList(sourceElement._lockedAllExceptAttributesList, parentElement._lockedAllExceptAttributesList, saveMode);
  985.                     if (parentElement._lockedAllExceptElementsList != null)
  986.                         _lockedAllExceptElementsList = UnMergeLockList(sourceElement._lockedAllExceptElementsList, parentElement._lockedAllExceptElementsList, saveMode);
  987.                 }
  988.                
  989.                 ConfigurationPropertyCollection props = Properties;
  990.                 ConfigurationPropertyCollection collectionKeys = null;
  991.                
  992.                 // check for props not in bag from source
  993.                 for (int index = 0; index < sourceElement.Values.Count; index++) {
  994.                     string key = sourceElement.Values.GetKey(index);
  995.                     object value = sourceElement.Values[index];
  996.                     ConfigurationProperty prop = (ConfigurationProperty)sourceElement.Properties[key];
  997.                     if (prop == null || (collectionKeys != null && !collectionKeys.Contains(prop.Name)))
  998.                         continue;
  999.                     if (typeof(ConfigurationElement).IsAssignableFrom(prop.Type)) {
  1000.                         hasAnyChildElements = true;
  1001.                     }
  1002.                     else {
  1003.                         if (value != s_nullPropertyValue) {
  1004.                             // this is for optional provider models keys
  1005.                             if (!props.Contains(key)) {
  1006.                                 // _values[key] = value;
  1007.                                 ConfigurationValueFlags valueFlags = sourceElement.Values.RetrieveFlags(key);
  1008.                                 _values.SetValue(key, value, valueFlags, null);
  1009.                                
  1010.                                 props.Add(prop);
  1011.                             }
  1012.                         }
  1013.                     }
  1014.                 }
  1015.                
  1016.                 foreach (ConfigurationProperty prop in Properties) {
  1017.                     if (prop == null || (collectionKeys != null && !collectionKeys.Contains(prop.Name))) {
  1018.                         continue;
  1019.                     }
  1020.                     if (typeof(ConfigurationElement).IsAssignableFrom(prop.Type)) {
  1021.                         hasAnyChildElements = true;
  1022.                     }
  1023.                     else {
  1024.                         object value = sourceElement.Values[prop.Name];
  1025.                        
  1026.                         // if the property is required or we are writing a full config make sure we have defaults
  1027.                         if ((prop.IsRequired == true || saveMode == ConfigurationSaveMode.Full) && (value == null || value == s_nullPropertyValue)) {
  1028.                             // If the default value is null, this means there wasnt a reasonable default for the value
  1029.                             // and there is nothing more we can do. Otherwise reset the value to the default
  1030.                            
  1031.                             // Note: 'null' should be used as default for non-empty strings instead
  1032.                             // of the current practice to use String.Epmty
  1033.                            
  1034.                             if (prop.DefaultValue != null) {
  1035.                                 value = prop.DefaultValue;
  1036.                                 // need to make sure required properties are persisted
  1037.                             }
  1038.                         }
  1039.                        
  1040.                         if (value != null && value != s_nullPropertyValue) {
  1041.                             object value2 = null;
  1042.                             if (parentElement != null)
  1043.                                 // Is there a parent
  1044.                                 value2 = parentElement.Values[prop.Name];
  1045.                             // if so get it's value
  1046.                             if (value2 == null)
  1047.                                 // no parent use default
  1048.                                 value2 = prop.DefaultValue;
  1049.                             // If changed and not same as parent write or required
  1050.                            
  1051.                             switch (saveMode) {
  1052.                                 case ConfigurationSaveMode.Minimal:
  1053.                                    
  1054.                                     {
  1055.                                         if (!Object.Equals(value, value2) || prop.IsRequired == true)
  1056.                                             _values[prop.Name] = value;
  1057.                                     }
  1058.                                     break;
  1059.                                 case ConfigurationSaveMode.Modified:
  1060.                                     // (value != null && value != s_nullPropertyValue) ||
  1061.                                    
  1062.                                     {
  1063.                                         bool modified = sourceElement.Values.IsModified(prop.Name);
  1064.                                         bool inherited = sourceElement.Values.IsInherited(prop.Name);
  1065.                                        
  1066.                                         // update the value if the property is required, modified or it was not inherited
  1067.                                         // Also update properties that ARE inherited when we are resetting the object
  1068.                                         // as long as the property is not the same as the default value for the property
  1069.                                         if ((prop.IsRequired || modified || !inherited) || (parentElement == null && inherited && !Object.Equals(value, value2))) {
  1070.                                             _values[prop.Name] = value;
  1071.                                         }
  1072.                                     }
  1073.                                     break;
  1074.                                 case ConfigurationSaveMode.Full:
  1075.                                    
  1076.                                     {
  1077.                                         if (value != null && value != s_nullPropertyValue)
  1078.                                             _values[prop.Name] = value;
  1079.                                         else
  1080.                                             _values[prop.Name] = value2;
  1081.                                        
  1082.                                     }
  1083.                                     break;
  1084.                             }
  1085.                         }
  1086.                     }
  1087.                 }
  1088.                
  1089.                 if (hasAnyChildElements) {
  1090.                     foreach (ConfigurationProperty prop in Properties) {
  1091.                         if (typeof(ConfigurationElement).IsAssignableFrom(prop.Type)) {
  1092.                             ConfigurationElement pElem = (ConfigurationElement)((parentElement != null) ? parentElement[prop] : null);
  1093.                             ConfigurationElement childElement = (ConfigurationElement)this[prop];
  1094.                             if ((ConfigurationElement)sourceElement[prop] != null)
  1095.                                 childElement.Unmerge((ConfigurationElement)sourceElement[prop], pElem, saveMode);
  1096.                         }
  1097.                        
  1098.                     }
  1099.                 }
  1100.             }
  1101.         }
  1102.        
  1103.         protected internal virtual bool SerializeToXmlElement(XmlWriter writer, string elementName)
  1104.         {
  1105.             bool DataToWrite = _bDataToWrite;
  1106.            
  1107.             // Don't write elements that are locked in the parent
  1108.             if ((_lockedElementsList != null && _lockedElementsList.DefinedInParent(elementName)) || (_lockedAllExceptElementsList != null && _lockedAllExceptElementsList.HasParentElements && !_lockedAllExceptElementsList.DefinedInParent(elementName))) {
  1109.                 return DataToWrite;
  1110.             }
  1111.            
  1112.             // check if there is anything to write...
  1113.             if (SerializeElement(null, false) == true) {
  1114.                 if (writer != null)
  1115.                     writer.WriteStartElement(elementName);
  1116.                 DataToWrite |= SerializeElement(writer, false);
  1117.                 if (writer != null)
  1118.                     writer.WriteEndElement();
  1119.             }
  1120.             return DataToWrite;
  1121.         }
  1122.        
  1123.         protected internal virtual bool SerializeElement(XmlWriter writer, bool serializeCollectionKey)
  1124.         {
  1125.             PreSerialize(writer);
  1126.            
  1127.             bool DataToWrite = _bDataToWrite;
  1128.             bool hasAnyChildElements = false;
  1129.             bool foundDefaultElement = false;
  1130.             ConfigurationPropertyCollection props = Properties;
  1131.             ConfigurationPropertyCollection collectionKeys = null;
  1132.            
  1133.             for (int index = 0; index < _values.Count; index++) {
  1134.                 string key = _values.GetKey(index);
  1135.                 object value = _values[index];
  1136.                
  1137.                 ConfigurationProperty prop = (ConfigurationProperty)props[key];
  1138.                 if (prop == null || (collectionKeys != null && !collectionKeys.Contains(prop.Name))) {
  1139.                     continue;
  1140.                 }
  1141.                
  1142.                 if (typeof(ConfigurationElement).IsAssignableFrom(prop.Type)) {
  1143.                     hasAnyChildElements = true;
  1144.                 }
  1145.                 else {
  1146.                     if ((_lockedAllExceptAttributesList != null && _lockedAllExceptAttributesList.HasParentElements && !_lockedAllExceptAttributesList.DefinedInParent(prop.Name)) || (_lockedAttributesList != null && _lockedAttributesList.DefinedInParent(prop.Name))) {
  1147.                         if (prop.IsRequired == true)
  1148.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_required_attribute_locked, prop.Name));
  1149.                         value = s_nullPropertyValue;
  1150.                     }
  1151.                    
  1152.                     if (value != s_nullPropertyValue) {
  1153.                         if (serializeCollectionKey == false || prop.IsKey == true) {
  1154.                             string xmlValue = null;
  1155.                            
  1156.                             // If this was an invalid string value and was cached - write it out as is
  1157.                             if (value is InvalidPropValue) {
  1158.                                 xmlValue = ((InvalidPropValue)value).Value;
  1159.                             }
  1160.                             else {
  1161.                                 prop.Validate(value);
  1162.                                 xmlValue = prop.ConvertToString(value);
  1163.                             }
  1164.                            
  1165.                             if ((xmlValue != null) && (writer != null)) {
  1166.                                 writer.WriteAttributeString(prop.Name, xmlValue);
  1167.                             }
  1168.                            
  1169.                             DataToWrite = DataToWrite || (xmlValue != null);
  1170.                         }
  1171.                     }
  1172.                 }
  1173.             }
  1174.             if (serializeCollectionKey == false) {
  1175.                 DataToWrite |= SerializeLockList(_lockedAttributesList, LockAttributesKey, writer);
  1176.                 DataToWrite |= SerializeLockList(_lockedAllExceptAttributesList, LockAllAttributesExceptKey, writer);
  1177.                 DataToWrite |= SerializeLockList(_lockedElementsList, LockElementsKey, writer);
  1178.                 DataToWrite |= SerializeLockList(_lockedAllExceptElementsList, LockAllElementsExceptKey, writer);
  1179.                 if ((_fItemLocked & ConfigurationValueFlags.Locked) != 0 && (_fItemLocked & ConfigurationValueFlags.Inherited) == 0 && (_fItemLocked & ConfigurationValueFlags.XMLParentInherited) == 0) {
  1180.                     DataToWrite = true;
  1181.                     if (writer != null)
  1182.                         writer.WriteAttributeString(LockItemKey, true.ToString().ToLower(CultureInfo.InvariantCulture));
  1183.                 }
  1184.             }
  1185.             if (hasAnyChildElements) {
  1186.                 for (int index = 0; index < _values.Count; index++) {
  1187.                     string key = _values.GetKey(index);
  1188.                     object value = _values[index];
  1189.                    
  1190.                     ConfigurationProperty prop = (ConfigurationProperty)props[key];
  1191.                     // if we are writing a remove and the sub element is not part of the key don't write it.
  1192.                     if (serializeCollectionKey == false || prop.IsKey == true) {
  1193.                         if (value is ConfigurationElement) {
  1194.                             if (!((_lockedElementsList != null && _lockedElementsList.DefinedInParent(key)) || (_lockedAllExceptElementsList != null && _lockedAllExceptElementsList.HasParentElements && !_lockedAllExceptElementsList.DefinedInParent(key)))) {
  1195.                                
  1196.                                 ConfigurationElement elem = (ConfigurationElement)value;
  1197.                                
  1198.                                 if (prop.Name != ConfigurationProperty.DefaultCollectionPropertyName) {
  1199.                                     DataToWrite |= elem.SerializeToXmlElement(writer, prop.Name);
  1200.                                 }
  1201.                                 else if (!foundDefaultElement) {
  1202.                                     // Prevent the locks from serializing a second time since locks
  1203.                                     // on a default collection serialize with their parent node
  1204.                                     elem._lockedAttributesList = null;
  1205.                                     elem._lockedAllExceptAttributesList = null;
  1206.                                     elem._lockedElementsList = null;
  1207.                                     elem._lockedAllExceptElementsList = null;
  1208.                                    
  1209.                                     DataToWrite |= elem.SerializeElement(writer, false);
  1210.                                    
  1211.                                     foundDefaultElement = true;
  1212.                                 }
  1213.                                 else {
  1214.                                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_element_cannot_have_multiple_child_elements, prop.Name));
  1215.                                 }
  1216.                             }
  1217.                         }
  1218.                     }
  1219.                 }
  1220.             }
  1221.             return DataToWrite;
  1222.         }
  1223.         private bool SerializeLockList(ConfigurationLockCollection list, string elementKey, XmlWriter writer)
  1224.         {
  1225.             StringBuilder sb;
  1226.            
  1227.             sb = new StringBuilder();
  1228.            
  1229.             if (list != null) {
  1230.                 foreach (string key in list) {
  1231.                     if (!list.DefinedInParent(key)) {
  1232.                         if (sb.Length != 0)
  1233.                             sb.Append(',');
  1234.                         sb.Append((string)key);
  1235.                     }
  1236.                 }
  1237.             }
  1238.            
  1239.             if (writer != null && sb.Length != 0)
  1240.                 writer.WriteAttributeString(elementKey, sb.ToString());
  1241.             return (sb.Length != 0);
  1242.         }
  1243.         internal void ReportInvalidLock(string attribToLockTrim, ConfigurationLockCollectionType lockedType, ConfigurationValue value, string collectionProperties)
  1244.         {
  1245.             StringBuilder sb;
  1246.             sb = new StringBuilder();
  1247.            
  1248.             // Add the collection properties when locking elements
  1249.             if (!String.IsNullOrEmpty(collectionProperties) && ((lockedType == ConfigurationLockCollectionType.LockedElements) || (lockedType == ConfigurationLockCollectionType.LockedElementsExceptionList))) {
  1250.                 if (sb.Length != 0)
  1251.                     sb.Append(',');
  1252.                 sb.Append(collectionProperties);
  1253.             }
  1254.            
  1255.             // construct a list of valid lockable properties
  1256.             foreach (object _prop in Properties) {
  1257.                 ConfigurationProperty validProp = (ConfigurationProperty)_prop;
  1258.                 if (validProp.Name != LockAttributesKey && validProp.Name != LockAllAttributesExceptKey && validProp.Name != LockElementsKey && validProp.Name != LockAllElementsExceptKey) {
  1259.                     if ((lockedType == ConfigurationLockCollectionType.LockedElements) || (lockedType == ConfigurationLockCollectionType.LockedElementsExceptionList)) {
  1260.                         if (typeof(ConfigurationElement).IsAssignableFrom(validProp.Type)) {
  1261.                             if (sb.Length != 0)
  1262.                                 sb.Append(", ");
  1263.                             sb.Append("'");
  1264.                             sb.Append(validProp.Name);
  1265.                             sb.Append("'");
  1266.                         }
  1267.                     }
  1268.                     else {
  1269.                         if (!typeof(ConfigurationElement).IsAssignableFrom(validProp.Type)) {
  1270.                             if (sb.Length != 0)
  1271.                                 sb.Append(", ");
  1272.                             sb.Append("'");
  1273.                             sb.Append(validProp.Name);
  1274.                             sb.Append("'");
  1275.                         }
  1276.                     }
  1277.                 }
  1278.             }
  1279.            
  1280.             string format = null;
  1281.            
  1282.             if ((lockedType == ConfigurationLockCollectionType.LockedElements) || (lockedType == ConfigurationLockCollectionType.LockedElementsExceptionList)) {
  1283.                 if (value != null)
  1284.                     format = SR.GetString(SR.Config_base_invalid_element_to_lock);
  1285.                 else
  1286.                     format = SR.GetString(SR.Config_base_invalid_element_to_lock_by_add);
  1287.                
  1288.             }
  1289.             else {
  1290.                 if (value != null)
  1291.                     format = SR.GetString(SR.Config_base_invalid_attribute_to_lock);
  1292.                 else
  1293.                     format = SR.GetString(SR.Config_base_invalid_attribute_to_lock_by_add);
  1294.             }
  1295.             if (value != null)
  1296.                 throw new ConfigurationErrorsException(string.Format(CultureInfo.CurrentCulture, format, attribToLockTrim, sb.ToString()), value.SourceInfo.FileName, value.SourceInfo.LineNumber);
  1297.             else
  1298.                 throw new ConfigurationErrorsException(string.Format(CultureInfo.CurrentCulture, format, attribToLockTrim, sb.ToString()));
  1299.         }
  1300.        
  1301.         private ConfigurationLockCollection ParseLockedAttributes(ConfigurationValue value, ConfigurationLockCollectionType lockType)
  1302.         {
  1303.             // check that only actual properties are in the lock attribute
  1304.             ConfigurationLockCollection localLockedAttributesList = new ConfigurationLockCollection(this, lockType);
  1305.             string attributeList = (string)(value.Value);
  1306.            
  1307.             if (string.IsNullOrEmpty(attributeList)) {
  1308.                 if (lockType == ConfigurationLockCollectionType.LockedAttributes)
  1309.                     throw new ConfigurationErrorsException(SR.GetString(SR.Empty_attribute, LockAttributesKey), value.SourceInfo.FileName, value.SourceInfo.LineNumber);
  1310.                 if (lockType == ConfigurationLockCollectionType.LockedElements)
  1311.                     throw new ConfigurationErrorsException(SR.GetString(SR.Empty_attribute, LockElementsKey), value.SourceInfo.FileName, value.SourceInfo.LineNumber);
  1312.                 if (lockType == ConfigurationLockCollectionType.LockedExceptionList)
  1313.                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_empty_lock_attributes_except, LockAllAttributesExceptKey, LockAttributesKey), value.SourceInfo.FileName, value.SourceInfo.LineNumber);
  1314.                 if (lockType == ConfigurationLockCollectionType.LockedElementsExceptionList)
  1315.                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_empty_lock_element_except, LockAllElementsExceptKey, LockElementsKey), value.SourceInfo.FileName, value.SourceInfo.LineNumber);
  1316.             }
  1317.            
  1318.             string[] attribsToLock = attributeList.Split(new char[] {',', ':', ';'});
  1319.             foreach (string attribToLock in attribsToLock) {
  1320.                 string attribToLockTrim = attribToLock.Trim();
  1321.                 if (!String.IsNullOrEmpty(attribToLockTrim)) {
  1322.                     // validate that the locks are good
  1323.                     if (!((lockType == ConfigurationLockCollectionType.LockedElements || lockType == ConfigurationLockCollectionType.LockedAttributes) && attribToLockTrim == LockAll)) {
  1324.                         ConfigurationProperty propToLock = Properties[attribToLockTrim];
  1325.                        
  1326.                         // if the prop does not exist
  1327.                         // or it is the lockattributes keyword
  1328.                         // or it is the lockattributes keyword
  1329.                         // or it is the lockelements keyword
  1330.                         // or if not locking elements but the property is a element
  1331.                         // or if locking elements but the property is not an element
  1332.                         if (propToLock == null || attribToLockTrim == LockAttributesKey || attribToLockTrim == LockAllAttributesExceptKey || attribToLockTrim == LockElementsKey || (lockType != ConfigurationLockCollectionType.LockedElements && lockType != ConfigurationLockCollectionType.LockedElementsExceptionList && typeof(ConfigurationElement).IsAssignableFrom(propToLock.Type)) || ((lockType == ConfigurationLockCollectionType.LockedElements || lockType == ConfigurationLockCollectionType.LockedElementsExceptionList) && !typeof(ConfigurationElement).IsAssignableFrom(propToLock.Type))) {
  1333.                             // check to see if this is a collection and we are locking a collection element
  1334.                            
  1335.                             ConfigurationElementCollection collection = this as ConfigurationElementCollection;
  1336.                             // this is not a collection but it may contain a default collection
  1337.                             if (collection == null && Properties.DefaultCollectionProperty != null) {
  1338.                                 collection = this[Properties.DefaultCollectionProperty] as ConfigurationElementCollection;
  1339.                             }
  1340.                             // If the collection type is not element then the lock is bogus
  1341.                             if (collection == null || lockType == ConfigurationLockCollectionType.LockedAttributes || lockType == ConfigurationLockCollectionType.LockedExceptionList) {
  1342.                                 ReportInvalidLock(attribToLockTrim, lockType, value, null);
  1343.                             }
  1344.                             else if (!collection.IsLockableElement(attribToLockTrim)) {
  1345.                                 ReportInvalidLock(attribToLockTrim, lockType, value, collection.LockableElements);
  1346.                             }
  1347.                         }
  1348.                         if (propToLock != null && propToLock.IsRequired == true)
  1349.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_required_attribute_lock_attempt, propToLock.Name));
  1350.                     }
  1351.                    
  1352.                    
  1353.                     // concatenate the new attribute.
  1354.                     localLockedAttributesList.Add(attribToLockTrim, ConfigurationValueFlags.Default);
  1355.                     // Mark as local
  1356.                 }
  1357.             }
  1358.             return localLockedAttributesList;
  1359.         }
  1360.        
  1361.         private StringCollection IntersectLockCollections(ConfigurationLockCollection Collection1, ConfigurationLockCollection Collection2)
  1362.         {
  1363.             ConfigurationLockCollection smallCollection = Collection1.Count < Collection2.Count ? Collection1 : Collection2;
  1364.             ConfigurationLockCollection largeCollection = Collection1.Count >= Collection2.Count ? Collection1 : Collection2;
  1365.             StringCollection intersectionCollection = new StringCollection();
  1366.            
  1367.             foreach (string key in smallCollection) {
  1368.                 if (largeCollection.Contains(key) || key == ElementTagName)
  1369.                     intersectionCollection.Add(key);
  1370.                 // add the local copy
  1371.             }
  1372.             return intersectionCollection;
  1373.         }
  1374.        
  1375.        
  1376.         protected internal virtual void DeserializeElement(XmlReader reader, bool serializeCollectionKey)
  1377.         {
  1378.             ConfigurationPropertyCollection props = Properties;
  1379.             ConfigurationValue LockedAttributesList = null;
  1380.             ConfigurationValue LockedAllExceptList = null;
  1381.             ConfigurationValue LockedElementList = null;
  1382.             ConfigurationValue LockedAllElementsExceptList = null;
  1383.             bool ItemLockedLocally = false;
  1384.            
  1385.             _bElementPresent = true;
  1386.            
  1387.             ConfigurationElement defaultCollection = null;
  1388.             ConfigurationProperty defaultCollectionProperty = props != null ? props.DefaultCollectionProperty : null;
  1389.             if (defaultCollectionProperty != null) {
  1390.                 defaultCollection = (ConfigurationElement)this[defaultCollectionProperty];
  1391.             }
  1392.            
  1393.             // Process attributes
  1394.             _elementTagName = reader.Name;
  1395.             PropertySourceInfo rootInfo = new PropertySourceInfo(reader);
  1396.             _values.SetValue(reader.Name, null, ConfigurationValueFlags.Modified, rootInfo);
  1397.             _values.SetValue(DefaultCollectionPropertyName, defaultCollection, ConfigurationValueFlags.Modified, rootInfo);
  1398.            
  1399.             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)) {
  1400.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_element_locked, reader.Name), reader);
  1401.             }
  1402.            
  1403.            
  1404.             if (reader.AttributeCount > 0) {
  1405.                 while (reader.MoveToNextAttribute()) {
  1406.                    
  1407.                     string propertyName = reader.Name;
  1408.                     if ((_lockedAttributesList != null && (_lockedAttributesList.Contains(propertyName) || _lockedAttributesList.Contains(LockAll))) || (_lockedAllExceptAttributesList != null && !_lockedAllExceptAttributesList.Contains(propertyName))) {
  1409.                         if (propertyName != LockAttributesKey && propertyName != LockAllAttributesExceptKey)
  1410.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_attribute_locked, propertyName), reader);
  1411.                     }
  1412.                    
  1413.                     ConfigurationProperty prop = props != null ? props[propertyName] : null;
  1414.                     if (prop != null) {
  1415.                         if (serializeCollectionKey && !prop.IsKey) {
  1416.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_unrecognized_attribute, propertyName), reader);
  1417.                         }
  1418.                        
  1419.                         _values.SetValue(propertyName, DeserializePropertyValue(prop, reader), ConfigurationValueFlags.Modified, new PropertySourceInfo(reader));
  1420.                        
  1421.                     }
  1422.                     // if (deserializing a remove OR an add that does not handle optional attributes)
  1423.                     else if (propertyName == LockItemKey) {
  1424.                         try {
  1425.                             ItemLockedLocally = bool.Parse(reader.Value);
  1426.                         }
  1427.                         catch {
  1428.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_invalid_boolean_attribute, propertyName), reader);
  1429.                         }
  1430.                     }
  1431.                     else if (propertyName == LockAttributesKey) {
  1432.                         LockedAttributesList = new ConfigurationValue(reader.Value, ConfigurationValueFlags.Default, new PropertySourceInfo(reader));
  1433.                     }
  1434.                     else if (propertyName == LockAllAttributesExceptKey) {
  1435.                         LockedAllExceptList = new ConfigurationValue(reader.Value, ConfigurationValueFlags.Default, new PropertySourceInfo(reader));
  1436.                     }
  1437.                     else if (propertyName == LockElementsKey) {
  1438.                         LockedElementList = new ConfigurationValue(reader.Value, ConfigurationValueFlags.Default, new PropertySourceInfo(reader));
  1439.                     }
  1440.                     else if (propertyName == LockAllElementsExceptKey) {
  1441.                         LockedAllElementsExceptList = new ConfigurationValue(reader.Value, ConfigurationValueFlags.Default, new PropertySourceInfo(reader));
  1442.                     }
  1443.                     else if (serializeCollectionKey || !OnDeserializeUnrecognizedAttribute(propertyName, reader.Value)) {
  1444.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_unrecognized_attribute, propertyName), reader);
  1445.                     }
  1446.                 }
  1447.             }
  1448.            
  1449.             reader.MoveToElement();
  1450.            
  1451.             // Check for nested elements.
  1452.             try {
  1453.                
  1454.                 HybridDictionary nodeFound = new HybridDictionary();
  1455.                 if (!reader.IsEmptyElement) {
  1456.                     while (reader.Read()) {
  1457.                         if (reader.NodeType == XmlNodeType.Element) {
  1458.                             string propertyName = reader.Name;
  1459.                            
  1460.                             CheckLockedElement(propertyName, null);
  1461.                            
  1462.                             ConfigurationProperty prop = props != null ? props[propertyName] : null;
  1463.                             if (prop != null) {
  1464.                                 if (typeof(ConfigurationElement).IsAssignableFrom(prop.Type)) {
  1465.                                     if (nodeFound.Contains(propertyName))
  1466.                                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_element_cannot_have_multiple_child_elements, propertyName), reader);
  1467.                                     nodeFound.Add(propertyName, propertyName);
  1468.                                     ConfigurationElement childElement = (ConfigurationElement)this[prop];
  1469.                                     childElement.DeserializeElement(reader, serializeCollectionKey);
  1470.                                    
  1471.                                     // Validate the new element with the per-property Validator
  1472.                                     // Note that the per-type validator for childElement has been already executed as part of Deserialize
  1473.                                     ValidateElement(childElement, prop.Validator, false);
  1474.                                 }
  1475.                                 else {
  1476.                                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_property_is_not_a_configuration_element, propertyName), reader);
  1477.                                 }
  1478.                             }
  1479.                             else if (!OnDeserializeUnrecognizedElement(propertyName, reader)) {
  1480.                                 // Let the default collection, if there is one, handle this node.
  1481.                                 if (defaultCollection == null || !defaultCollection.OnDeserializeUnrecognizedElement(propertyName, reader)) {
  1482.                                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_unrecognized_element_name, propertyName), reader);
  1483.                                 }
  1484.                             }
  1485.                         }
  1486.                         else if (reader.NodeType == XmlNodeType.EndElement) {
  1487.                             break;
  1488.                         }
  1489.                         else if ((reader.NodeType == XmlNodeType.CDATA) || (reader.NodeType == XmlNodeType.Text)) {
  1490.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_section_invalid_content), reader);
  1491.                         }
  1492.                     }
  1493.                 }
  1494.                
  1495.                 EnsureRequiredProperties(serializeCollectionKey);
  1496.                
  1497.                 // Call the per-type validator for this object
  1498.                 ValidateElement(this, null, false);
  1499.             }
  1500.             catch (ConfigurationException e) {
  1501.                 // Catch the generic message from deserialization and include line info if necessary
  1502.                 if (e.Filename == null || e.Filename.Length == 0)
  1503.                     throw new ConfigurationErrorsException(e.Message, reader);
  1504.                 else
  1505.                     // give it some info
  1506.                     throw e;
  1507.             }
  1508.            
  1509.             if (ItemLockedLocally) {
  1510.                 SetLocked();
  1511.                 _fItemLocked = ConfigurationValueFlags.Locked;
  1512.             }
  1513.            
  1514.             if (LockedAttributesList != null) {
  1515.                 if (_lockedAttributesList == null)
  1516.                     _lockedAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedAttributes);
  1517.                 foreach (string key in ParseLockedAttributes(LockedAttributesList, ConfigurationLockCollectionType.LockedAttributes)) {
  1518.                     if (!_lockedAttributesList.Contains(key))
  1519.                         _lockedAttributesList.Add(key, ConfigurationValueFlags.Default);
  1520.                     else
  1521.                         // add the local copy
  1522.                         _lockedAttributesList.Add(key, ConfigurationValueFlags.Modified | ConfigurationValueFlags.Inherited);
  1523.                     // add the local copy
  1524.                 }
  1525.             }
  1526.             if (LockedAllExceptList != null) {
  1527.                 ConfigurationLockCollection newCollection = ParseLockedAttributes(LockedAllExceptList, ConfigurationLockCollectionType.LockedExceptionList);
  1528.                 if (_lockedAllExceptAttributesList == null) {
  1529.                     _lockedAllExceptAttributesList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedExceptionList, String.Empty, newCollection);
  1530.                     _lockedAllExceptAttributesList.ClearSeedList();
  1531.                     // Prevent the list from thinking this was set by a parent.
  1532.                 }
  1533.                 StringCollection intersectionCollection = IntersectLockCollections(_lockedAllExceptAttributesList, newCollection);
  1534.                 /*
  1535.                 if (intersectionCollection.Count == 0) {
  1536.                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_empty_lock_attributes_except_effective,
  1537.                                                                         LockAllAttributesExceptKey,
  1538.                                                                         LockedAllExceptList.Value,
  1539.                                                                         LockAttributesKey),
  1540.                                                                         LockedAllExceptList.SourceInfo.FileName,
  1541.                                                                         LockedAllExceptList.SourceInfo.LineNumber);
  1542.                 }
  1543.                 */               
  1544. _lockedAllExceptAttributesList.ClearInternal(false);
  1545.                 foreach (string key in intersectionCollection) {
  1546.                     _lockedAllExceptAttributesList.Add(key, ConfigurationValueFlags.Default);
  1547.                 }
  1548.             }
  1549.             if (LockedElementList != null) {
  1550.                 if (_lockedElementsList == null)
  1551.                     _lockedElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElements);
  1552.                
  1553.                 ConfigurationLockCollection localLockedElementList = ParseLockedAttributes(LockedElementList, ConfigurationLockCollectionType.LockedElements);
  1554.                
  1555.                 ConfigurationElementCollection collection = null;
  1556.                 // this is not a collection but it may contain a default collection
  1557.                 if (props.DefaultCollectionProperty != null) {
  1558.                     collection = this[props.DefaultCollectionProperty] as ConfigurationElementCollection;
  1559.                     if (collection != null && collection._lockedElementsList == null)
  1560.                         collection._lockedElementsList = _lockedElementsList;
  1561.                 }
  1562.                
  1563.                 foreach (string key in localLockedElementList) {
  1564.                     if (!_lockedElementsList.Contains(key)) {
  1565.                         _lockedElementsList.Add(key, ConfigurationValueFlags.Default);
  1566.                         // add the local copy
  1567.                         ConfigurationProperty propToLock = Properties[key];
  1568.                         if (propToLock != null && typeof(ConfigurationElement).IsAssignableFrom(propToLock.Type)) {
  1569.                             ((ConfigurationElement)this[key]).SetLocked();
  1570.                         }
  1571.                         if (key == LockAll) {
  1572.                             foreach (ConfigurationProperty prop in Properties) {
  1573.                                 if (!string.IsNullOrEmpty(prop.Name) && typeof(ConfigurationElement).IsAssignableFrom(prop.Type)) {
  1574.                                     ((ConfigurationElement)this[prop]).SetLocked();
  1575.                                 }
  1576.                             }
  1577.                         }
  1578.                        
  1579.                     }
  1580.                 }
  1581.             }
  1582.            
  1583.             if (LockedAllElementsExceptList != null) {
  1584.                 ConfigurationLockCollection newCollection = ParseLockedAttributes(LockedAllElementsExceptList, ConfigurationLockCollectionType.LockedElementsExceptionList);
  1585.                 if (_lockedAllExceptElementsList == null) {
  1586.                     _lockedAllExceptElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElementsExceptionList, _elementTagName, newCollection);
  1587.                     _lockedAllExceptElementsList.ClearSeedList();
  1588.                 }
  1589.                
  1590.                 StringCollection intersectionCollection = IntersectLockCollections(_lockedAllExceptElementsList, newCollection);
  1591.                
  1592.                 ConfigurationElementCollection collection = null;
  1593.                 // this is not a collection but it may contain a default collection
  1594.                 if (props.DefaultCollectionProperty != null) {
  1595.                     collection = this[props.DefaultCollectionProperty] as ConfigurationElementCollection;
  1596.                     if (collection != null && collection._lockedAllExceptElementsList == null)
  1597.                         collection._lockedAllExceptElementsList = _lockedAllExceptElementsList;
  1598.                 }
  1599.                
  1600.                 _lockedAllExceptElementsList.ClearInternal(false);
  1601.                 foreach (string key in intersectionCollection) {
  1602.                     if (!_lockedAllExceptElementsList.Contains(key) || key == ElementTagName)
  1603.                         _lockedAllExceptElementsList.Add(key, ConfigurationValueFlags.Default);
  1604.                     // add the local copy
  1605.                 }
  1606.                
  1607.                 foreach (ConfigurationProperty prop in Properties) {
  1608.                     if (!(string.IsNullOrEmpty(prop.Name) || _lockedAllExceptElementsList.Contains(prop.Name)) && typeof(ConfigurationElement).IsAssignableFrom(prop.Type)) {
  1609.                         ((ConfigurationElement)this[prop]).SetLocked();
  1610.                     }
  1611.                 }
  1612.                
  1613.             }
  1614.            
  1615.             // Make sure default collections use the same lock element lists
  1616.             if (defaultCollectionProperty != null) {
  1617.                 defaultCollection = (ConfigurationElement)this[defaultCollectionProperty];
  1618.                 if (_lockedElementsList == null) {
  1619.                     _lockedElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElements);
  1620.                 }
  1621.                 defaultCollection._lockedElementsList = _lockedElementsList;
  1622.                 if (_lockedAllExceptElementsList == null) {
  1623.                     _lockedAllExceptElementsList = new ConfigurationLockCollection(this, ConfigurationLockCollectionType.LockedElementsExceptionList, reader.Name);
  1624.                     _lockedAllExceptElementsList.ClearSeedList();
  1625.                 }
  1626.                 defaultCollection._lockedAllExceptElementsList = _lockedAllExceptElementsList;
  1627.             }
  1628.            
  1629.             // This has to be the last thing to execute
  1630.             PostDeserialize();
  1631.         }
  1632.         private object DeserializePropertyValue(ConfigurationProperty prop, XmlReader reader)
  1633.         {
  1634.             Debug.Assert(prop != null, "prop != null");
  1635.             Debug.Assert(reader != null, "reader != null");
  1636.            
  1637.             // By default we try to load (i.e. parse/validate ) all properties
  1638.             // If a property value is invalid ( cannot be parsed or is not valid ) we will keep the value
  1639.             // as string ( from the xml ) and will write it out unchanged if needed
  1640.             // If the property value is needed by users the actuall exception will be thrown
  1641.            
  1642.             string xmlValue = reader.Value;
  1643.             object propertyValue = null;
  1644.            
  1645.             try {
  1646.                 propertyValue = prop.ConvertFromString(xmlValue);
  1647.                
  1648.                 // Validate the loaded and converted value
  1649.                 prop.Validate(propertyValue);
  1650.             }
  1651.             catch (ConfigurationException ce) {
  1652.                 // If the error is incomplete - complete it :)
  1653.                 if (string.IsNullOrEmpty(ce.Filename)) {
  1654.                     ce = new ConfigurationErrorsException(ce.Message, reader);
  1655.                 }
  1656.                
  1657.                 // Cannot parse/validate the value. Keep it as string
  1658.                 propertyValue = new InvalidPropValue(xmlValue, ce);
  1659.             }
  1660.             catch {
  1661.                 // If this is an exception related to the parsing/validating the
  1662.                 // value ConfigurationErrorsException should be thrown instead.
  1663.                 // If not - the exception is ok to surface out of here
  1664.                 Debug.Fail("Unknown exception type thrown");
  1665.             }
  1666.            
  1667.             return propertyValue;
  1668.         }
  1669.        
  1670.         static internal void ValidateElement(ConfigurationElement elem, ConfigurationValidatorBase propValidator, bool recursive)
  1671.         {
  1672.             // Validate a config element with the per-type validator when a per-property ( propValidator ) is not supplied
  1673.             // or with the per-prop validator when the element ( elem ) is a child property of another configuration element
  1674.            
  1675.             ConfigurationValidatorBase validator = propValidator;
  1676.            
  1677.             // Not a property - use the per-type validator
  1678.             if ((validator == null) && (elem.ElementProperty != null)) {
  1679.                 validator = elem.ElementProperty.Validator;
  1680.                
  1681.                 // Since ElementProperty can be overriden by derived classes we need to make sure that
  1682.                 // the validator supports the type of elem every time
  1683.                 if ((validator != null) && !validator.CanValidate(elem.GetType())) {
  1684.                     throw new ConfigurationErrorsException(SR.GetString(SR.Validator_does_not_support_elem_type, elem.GetType().Name));
  1685.                 }
  1686.             }
  1687.            
  1688.             try {
  1689.                 if (validator != null) {
  1690.                     validator.Validate(elem);
  1691.                 }
  1692.             }
  1693.             catch (ConfigurationException) {
  1694.                 // ConfigurationElement validators are allowed to throw ConfigurationErrorsException.
  1695.                 throw;
  1696.             }
  1697.             catch (Exception ex) {
  1698.                 throw new ConfigurationErrorsException(SR.GetString(SR.Validator_element_not_valid, elem._elementTagName, ex.Message));
  1699.             }
  1700.             catch {
  1701.                 throw new ConfigurationErrorsException(SR.GetString(SR.Validator_element_not_valid, elem._elementTagName, ExceptionUtil.NoExceptionInformation));
  1702.             }
  1703.            
  1704.             if (recursive == true) {
  1705.                 if (elem is ConfigurationElementCollection) {
  1706.                     if (elem is ConfigurationElementCollection) {
  1707.                         IEnumerator it = ((ConfigurationElementCollection)elem).GetElementsEnumerator();
  1708.                         while (it.MoveNext()) {
  1709.                             ValidateElement((ConfigurationElement)it.Current, null, true);
  1710.                         }
  1711.                     }
  1712.                 }
  1713.                
  1714.                 // Validate all child elements recursively
  1715.                 for (int index = 0; index < elem.Values.Count; index++) {
  1716.                     ConfigurationElement value = elem.Values[index] as ConfigurationElement;
  1717.                    
  1718.                     if (value != null) {
  1719.                         // Run the per-type validator on the child element and proceed with validation in subelements
  1720.                         // Note we dont run the per-property validator here since we run those when the property value is set
  1721.                         ValidateElement(value, null, true);
  1722.                         // per-type
  1723.                     }
  1724.                 }
  1725.             }
  1726.         }
  1727.        
  1728.         private void EnsureRequiredProperties(bool ensureKeysOnly)
  1729.         {
  1730.             ConfigurationPropertyCollection props = Properties;
  1731.            
  1732.             // Make sure all required properties are here
  1733.             if (props != null) {
  1734.                 foreach (ConfigurationProperty prop in props) {
  1735.                     // The property is required but no value was found
  1736.                     if (prop.IsRequired && !_values.Contains(prop.Name)) {
  1737.                         // Required properties can be ommited when we need only the keys to be there
  1738.                         if (!ensureKeysOnly || prop.IsKey) {
  1739.                             _values[prop.Name] = OnRequiredPropertyNotFound(prop.Name);
  1740.                         }
  1741.                     }
  1742.                 }
  1743.             }
  1744.         }
  1745.         protected virtual object OnRequiredPropertyNotFound(string name)
  1746.         {
  1747.             // Derivied classes can override this to return a value for a required property that is missing
  1748.             // Here we treat this as an error though
  1749.            
  1750.             throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_required_attribute_missing, name), PropertyFileName(name), PropertyLineNumber(name));
  1751.            
  1752.         }
  1753.         protected virtual void PostDeserialize()
  1754.         {
  1755.             // Please try to not add code in here
  1756.         }
  1757.         protected virtual void PreSerialize(XmlWriter writer)
  1758.         {
  1759.             // Please try to not add code in here
  1760.         }
  1761.        
  1762.         protected virtual bool OnDeserializeUnrecognizedAttribute(string name, string value)
  1763.         {
  1764.             return false;
  1765.         }
  1766.        
  1767.         protected virtual bool OnDeserializeUnrecognizedElement(string elementName, XmlReader reader)
  1768.         {
  1769.             return false;
  1770.         }
  1771.        
  1772.         // Element
  1773.         //
  1774.         // Retrieve information specific to the element
  1775.         //
  1776.         public ElementInformation ElementInformation {
  1777.             get {
  1778.                 if (_evaluationElement == null) {
  1779.                     _evaluationElement = new ElementInformation(this);
  1780.                 }
  1781.                 return _evaluationElement;
  1782.             }
  1783.         }
  1784.        
  1785.         // EvaluationContext
  1786.         //
  1787.         // Retrieve information specific to the context of how we are
  1788.         // being evaluated
  1789.         //
  1790.         protected ContextInformation EvaluationContext {
  1791.             get {
  1792.                 if (_evalContext == null) {
  1793.                     if (_configRecord == null) {
  1794.                         // This is not associated with a context, so throw
  1795.                         // failure
  1796.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_element_no_context));
  1797.                     }
  1798.                    
  1799.                     _evalContext = new ContextInformation(_configRecord);
  1800.                 }
  1801.                
  1802.                 return _evalContext;
  1803.             }
  1804.         }
  1805.        
  1806.         protected internal virtual ConfigurationElementProperty ElementProperty {
  1807.             get { return _elementProperty; }
  1808.         }
  1809.        
  1810.         internal ConfigurationLockCollection UnMergeLockList(ConfigurationLockCollection sourceLockList, ConfigurationLockCollection parentLockList, ConfigurationSaveMode saveMode)
  1811.         {
  1812.             if (sourceLockList.ExceptionList == false) {
  1813.                 switch (saveMode) {
  1814.                     case ConfigurationSaveMode.Modified:
  1815.                        
  1816.                         {
  1817.                             ConfigurationLockCollection tempLockList = new ConfigurationLockCollection(this, sourceLockList.LockType);
  1818.                             foreach (string lockedAttributeName in sourceLockList)
  1819.                                 if (!parentLockList.Contains(lockedAttributeName) || sourceLockList.IsValueModified(lockedAttributeName)) {
  1820.                                     tempLockList.Add(lockedAttributeName, ConfigurationValueFlags.Default);
  1821.                                 }
  1822.                             return tempLockList;
  1823.                         }
  1824.                         break;
  1825.                     case ConfigurationSaveMode.Minimal:
  1826.                        
  1827.                         {
  1828.                             ConfigurationLockCollection tempLockList = new ConfigurationLockCollection(this, sourceLockList.LockType);
  1829.                             foreach (string lockedAttributeName in sourceLockList)
  1830.                                 if (!parentLockList.Contains(lockedAttributeName)) {
  1831.                                     tempLockList.Add(lockedAttributeName, ConfigurationValueFlags.Default);
  1832.                                 }
  1833.                             return tempLockList;
  1834.                         }
  1835.                         break;
  1836.                 }
  1837.             }
  1838.             else {
  1839.                 // exception list write out the entire collection unless the entire collection
  1840.                 // came from the parent.
  1841.                 if (saveMode == ConfigurationSaveMode.Modified || saveMode == ConfigurationSaveMode.Minimal) {
  1842.                     bool sameAsParent = false;
  1843.                     if (sourceLockList.Count == parentLockList.Count) {
  1844.                         sameAsParent = true;
  1845.                         foreach (string lockedAttributeName in sourceLockList) {
  1846.                             if (!parentLockList.Contains(lockedAttributeName) || (sourceLockList.IsValueModified(lockedAttributeName) && saveMode == ConfigurationSaveMode.Modified)) {
  1847.                                 sameAsParent = false;
  1848.                             }
  1849.                         }
  1850.                     }
  1851.                     if (sameAsParent == true) {
  1852.                         return null;
  1853.                     }
  1854.                 }
  1855.             }
  1856.             return sourceLockList;
  1857.         }
  1858.        
  1859.         //
  1860.         // Return true if an attribute is one of our reserved locking attributes,
  1861.         // false otherwise.
  1862.         //
  1863.         static internal bool IsLockAttributeName(string name)
  1864.         {
  1865.             // optimize for common case that attribute name does not start with "lock"
  1866.             if (!StringUtil.StartsWith(name, "lock")) {
  1867.                 return false;
  1868.             }
  1869.            
  1870.             foreach (string lockAttributeName in s_lockAttributeNames) {
  1871.                 if (name == lockAttributeName) {
  1872.                     return true;
  1873.                 }
  1874.             }
  1875.            
  1876.             return false;
  1877.         }
  1878.     }
  1879. }

Developer Fusion