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

  1. //------------------------------------------------------------------------------
  2. // <copyright file="MgmtConfigurationRecord.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. namespace System.Configuration
  16. {
  17.     using System.CodeDom.Compiler;
  18.     using System.Collections;
  19.     using System.Collections.Generic;
  20.     using System.Collections.Specialized;
  21.     using System.Configuration.Internal;
  22.     using System.Globalization;
  23.     using System.IO;
  24.     using System.Reflection;
  25.     using System.Security;
  26.     using System.Security.Permissions;
  27.     using System.Text;
  28.     using System.Xml;
  29.    
  30.     internal sealed class MgmtConfigurationRecord : BaseConfigurationRecord
  31.     {
  32.         private const int DEFAULT_INDENT = 4;
  33.         private const int MAX_INDENT = 10;
  34.        
  35.         private Hashtable _sectionGroups;
  36.         // ConfigurationSectionGroups that have been evaluated,
  37.         // which may or may not be defined in this web.config file.
  38.         // config key -> ConfigurationSectionGroup
  39.         private Hashtable _sectionFactories;
  40.         // All inherited section declarations
  41.         // configKey -> FactoryId
  42.         private Hashtable _sectionGroupFactories;
  43.         // All inherited section group declarations
  44.         // configKey -> FactoryId
  45.         private Hashtable _removedSections;
  46.         // Sections that have been removed with ConfigurationSectionCollection.Remove()
  47.         // configKey -> configKey
  48.         private Hashtable _removedSectionGroups;
  49.         // Section groups that have been removed with ConfigurationSectionCollection.Remove()
  50.         // configKey -> configKey
  51.         private Hashtable _locationTags;
  52.         // List of all location tags encountered, even if empty
  53.         // locationSubPath -> locationSubPath
  54.         private HybridDictionary _streamInfoUpdates;
  55.         // List of StreamInfo, including the main config file, the configSource this record uses, and
  56.         // new configSource stream added thru API
  57.        
  58.         static internal MgmtConfigurationRecord Create(IInternalConfigRoot configRoot, IInternalConfigRecord parent, string configPath, string locationSubPath)
  59.         {
  60.            
  61.             MgmtConfigurationRecord configRecord = new MgmtConfigurationRecord();
  62.             configRecord.Init(configRoot, parent, configPath, locationSubPath);
  63.             return configRecord;
  64.         }
  65.        
  66.         // don't allow instantiation except by Create
  67.         private MgmtConfigurationRecord()
  68.         {
  69.         }
  70.        
  71.         private void Init(IInternalConfigRoot configRoot, IInternalConfigRecord parent, string configPath, string locationSubPath)
  72.         {
  73.            
  74.             base.Init(configRoot, (BaseConfigurationRecord)parent, configPath, locationSubPath);
  75.            
  76.             if (IsLocationConfig && (MgmtParent._locationTags == null || !MgmtParent._locationTags.Contains(_locationSubPath))) {
  77.                
  78.                 // By instantiating a "new" LocationSubPath class, we have implicitly
  79.                 // asked for one to be created
  80.                 _flags[ForceLocationWritten] = true;
  81.             }
  82.            
  83.             // Copy all stream information so that we can model changes to ConfigSource
  84.             InitStreamInfoUpdates();
  85.         }
  86.        
  87.         private void InitStreamInfoUpdates()
  88.         {
  89.             _streamInfoUpdates = new HybridDictionary(true);
  90.             if (ConfigStreamInfo.HasStreamInfos) {
  91.                 foreach (StreamInfo streamInfo in ConfigStreamInfo.StreamInfos.Values) {
  92.                     _streamInfoUpdates.Add(streamInfo.StreamName, streamInfo.Clone());
  93.                 }
  94.             }
  95.         }
  96.        
  97.         // The parent config record cast to this type
  98.         private MgmtConfigurationRecord MgmtParent {
  99.             get { return (MgmtConfigurationRecord)_parent; }
  100.         }
  101.        
  102.         // The IInternalConfigHost cast to UpdateConfigHost.
  103.         private UpdateConfigHost UpdateConfigHost {
  104.             get { return (UpdateConfigHost)Host; }
  105.         }
  106.        
  107.         // Class flags
  108.         static readonly SimpleBitVector32 MgmtClassFlags = new SimpleBitVector32(ClassSupportsKeepInputs | ClassIgnoreLocalErrors);
  109.        
  110.         protected override SimpleBitVector32 ClassFlags {
  111.             get { return MgmtClassFlags; }
  112.         }
  113.        
  114.         //
  115.         // Create the factory object that is used to create new instances of a ConfigurationSection.
  116.         // Our factory is a ConstructorInfo that creates the section.
  117.         //
  118.         protected override object CreateSectionFactory(FactoryRecord factoryRecord)
  119.         {
  120.            
  121.             // Get the type of the factory
  122.             Type type = TypeUtil.GetTypeWithReflectionPermission(Host, factoryRecord.FactoryTypeName, true);
  123.            
  124.             //
  125.             // If the type is not a ConfigurationSection, use the DefaultSection if the type
  126.             // implements IConfigurationSectionHandler.
  127.             //
  128.             if (!typeof(ConfigurationSection).IsAssignableFrom(type)) {
  129.                 TypeUtil.VerifyAssignableType(typeof(IConfigurationSectionHandler), type, true);
  130.                 type = typeof(DefaultSection);
  131.             }
  132.            
  133.             ConstructorInfo ctor = TypeUtil.GetConstructorWithReflectionPermission(type, typeof(ConfigurationSection), true);
  134.            
  135.             return ctor;
  136.         }
  137.        
  138.         //
  139.         // Create the ConfigurationSection.
  140.         //
  141.         protected override object CreateSection(bool inputIsTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, object parentConfig, ConfigXmlReader reader)
  142.         {
  143.             // Create an instance of the ConfigurationSection
  144.             ConstructorInfo ctor = (ConstructorInfo)factoryRecord.Factory;
  145.             ConfigurationSection configSection = (ConfigurationSection)TypeUtil.InvokeCtorWithReflectionPermission(ctor);
  146.            
  147.             // Attach the ConfigurationSection to this record
  148.             configSection.SectionInformation.AttachToConfigurationRecord(this, factoryRecord, sectionRecord);
  149.             configSection.CallInit();
  150.            
  151.             // Initialize the ConfigurationSection with XML or just its parent.
  152.             ConfigurationSection parentConfigSection = (ConfigurationSection)parentConfig;
  153.             configSection.Reset(parentConfigSection);
  154.             if (reader != null) {
  155.                 configSection.DeserializeSection(reader);
  156.             }
  157.            
  158.             // Clear the modified bit.
  159.             configSection.ResetModified();
  160.            
  161.             return configSection;
  162.         }
  163.        
  164.         //
  165.         // Create the type used to create new instances of a ConfigurationSectionGroup.
  166.         // Our factory is a ConstructorInfo that creates the section group.
  167.         //
  168.         private ConstructorInfo CreateSectionGroupFactory(FactoryRecord factoryRecord)
  169.         {
  170.             Type type;
  171.            
  172.             if (String.IsNullOrEmpty(factoryRecord.FactoryTypeName)) {
  173.                 type = typeof(ConfigurationSectionGroup);
  174.             }
  175.             else {
  176.                 type = TypeUtil.GetTypeWithReflectionPermission(Host, factoryRecord.FactoryTypeName, true);
  177.             }
  178.            
  179.             ConstructorInfo ctor = TypeUtil.GetConstructorWithReflectionPermission(type, typeof(ConfigurationSectionGroup), true);
  180.            
  181.             return ctor;
  182.         }
  183.        
  184.         //
  185.         // Ensure the existence of a section group factory, and return it.
  186.         //
  187.         private ConstructorInfo EnsureSectionGroupFactory(FactoryRecord factoryRecord)
  188.         {
  189.             ConstructorInfo factory = (ConstructorInfo)factoryRecord.Factory;
  190.             if (factory == null) {
  191.                 factory = CreateSectionGroupFactory(factoryRecord);
  192.                 factoryRecord.Factory = factory;
  193.             }
  194.            
  195.             return factory;
  196.         }
  197.        
  198.        
  199.         //
  200.         // Create a new ConfigurationSection with the same values as the parent.
  201.         // We must use a different instance than the parent, as the parent is cached
  202.         // by the config system and the child ConfigurationSection may change due to
  203.         // user interaction.
  204.         //
  205.         protected override object UseParentResult(string configKey, object parentResult, SectionRecord sectionRecord)
  206.         {
  207.             FactoryRecord factoryRecord = FindFactoryRecord(configKey, false);
  208.             if (factoryRecord == null) {
  209.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_unrecognized_configuration_section, configKey));
  210.             }
  211.            
  212.             object result = CallCreateSection(false, factoryRecord, sectionRecord, parentResult, null, null, -1);
  213.             return result;
  214.         }
  215.        
  216.         //
  217.         // There is no runtime object at designtime - always return the result.
  218.         //
  219.         protected override object GetRuntimeObject(object result)
  220.         {
  221.             return result;
  222.         }
  223.        
  224.         //
  225.         // Return the section result cast to a ConfigurationSection,
  226.         // or null if the section does not exist or has not been evaluated.
  227.         //
  228.         private ConfigurationSection GetConfigSection(string configKey)
  229.         {
  230.             SectionRecord sectionRecord = GetSectionRecord(configKey, false);
  231.             if (sectionRecord != null && sectionRecord.HasResult) {
  232.                 return (ConfigurationSection)sectionRecord.Result;
  233.             }
  234.             else {
  235.                 return null;
  236.             }
  237.         }
  238.        
  239.         //
  240.         // Return the collection of ConfigurationSectionGroups.
  241.         //
  242.         private Hashtable SectionGroups {
  243.             get {
  244.                 if (_sectionGroups == null) {
  245.                     _sectionGroups = new Hashtable();
  246.                 }
  247.                
  248.                 return _sectionGroups;
  249.             }
  250.         }
  251.        
  252.         //
  253.         // Return the collection of removed sections.
  254.         //
  255.         private Hashtable RemovedSections {
  256.             get {
  257.                 if (_removedSections == null) {
  258.                     _removedSections = new Hashtable();
  259.                 }
  260.                
  261.                 return _removedSections;
  262.             }
  263.         }
  264.        
  265.         //
  266.         // Return the collection of removed section groups.
  267.         //
  268.         private Hashtable RemovedSectionGroups {
  269.             get {
  270.                 if (_removedSectionGroups == null) {
  271.                     _removedSectionGroups = new Hashtable();
  272.                 }
  273.                
  274.                 return _removedSectionGroups;
  275.             }
  276.         }
  277.        
  278.         //
  279.         // Lookup a section group. Return null if it doesn't exist or hasn't been evaluated.
  280.         //
  281.         internal ConfigurationSectionGroup LookupSectionGroup(string configKey)
  282.         {
  283.             ConfigurationSectionGroup configSectionGroup = null;
  284.             if (_sectionGroups != null) {
  285.                 configSectionGroup = (ConfigurationSectionGroup)_sectionGroups[configKey];
  286.             }
  287.            
  288.             return configSectionGroup;
  289.         }
  290.        
  291.         // Returns the ConfigurationSectionGroup of the configKey.
  292.         // The ConfigurationSectionGroup is created if it doesn't exist.
  293.         // This method only returns null if a FactoryRecord does not exist for the
  294.         // desired configKey.
  295.         internal ConfigurationSectionGroup GetSectionGroup(string configKey)
  296.         {
  297.             ConfigurationSectionGroup configSectionGroup = LookupSectionGroup(configKey);
  298.             if (configSectionGroup == null) {
  299.                 BaseConfigurationRecord configRecord;
  300.                 FactoryRecord factoryRecord = FindFactoryRecord(configKey, false, out configRecord);
  301.                 if (factoryRecord == null) {
  302.                     return null;
  303.                 }
  304.                
  305.                 if (!factoryRecord.IsGroup) {
  306.                     throw ExceptionUtil.ParameterInvalid("sectionGroupName");
  307.                 }
  308.                
  309.                 if (factoryRecord.FactoryTypeName == null) {
  310.                     //
  311.                     // If no type is defined for the section group, return a base ConfigurationSectionGroup.
  312.                     // For example:
  313.                     // <configSections>
  314.                     // <sectionGroup name="mySectionGroup" />
  315.                     // </configSections>
  316.                     //
  317.                     configSectionGroup = new ConfigurationSectionGroup();
  318.                 }
  319.                 else {
  320.                     //
  321.                     // Create the section group of the desired type.
  322.                     // For example:
  323.                     // <configSections>
  324.                     // <sectionGroup name="mySectionGroup" type="MySectionGroupType, acme" />
  325.                     // </configSections>
  326.                     //
  327.                     ConstructorInfo ctor = EnsureSectionGroupFactory(factoryRecord);
  328.                    
  329.                     try {
  330.                         configSectionGroup = (ConfigurationSectionGroup)TypeUtil.InvokeCtorWithReflectionPermission(ctor);
  331.                     }
  332.                     catch (Exception e) {
  333.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_exception_creating_section_handler, factoryRecord.ConfigKey), e, factoryRecord);
  334.                     }
  335.                     catch {
  336.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_exception_creating_section_handler, factoryRecord.ConfigKey), factoryRecord);
  337.                     }
  338.                 }
  339.                
  340.                 configSectionGroup.AttachToConfigurationRecord(this, factoryRecord);
  341.                
  342.                 // Add it to the collection
  343.                 SectionGroups[configKey] = configSectionGroup;
  344.             }
  345.            
  346.             return configSectionGroup;
  347.         }
  348.        
  349.         //
  350.         // Create a collection of all location tags encountered in the file.
  351.         //
  352.         internal ConfigurationLocationCollection GetLocationCollection(Configuration config)
  353.         {
  354.             ArrayList locations = new ArrayList();
  355.            
  356.             // Now add the other empty location sections we recorded
  357.             if (_locationTags != null) {
  358.                 foreach (string subPath in _locationTags.Values) {
  359.                     locations.Add(new ConfigurationLocation(config, subPath));
  360.                 }
  361.             }
  362.            
  363.             return new ConfigurationLocationCollection(locations);
  364.         }
  365.        
  366.         //
  367.         // AddLocation
  368.         //
  369.         // Record all location tags in the config file, even if they are empty.
  370.         //
  371.         protected override void AddLocation(string locationSubPath)
  372.         {
  373.             if (_locationTags == null) {
  374.                 _locationTags = new Hashtable(StringComparer.OrdinalIgnoreCase);
  375.             }
  376.            
  377.             _locationTags[locationSubPath] = locationSubPath;
  378.         }
  379.        
  380.         //
  381.         // Collection of all section factories, both in this file and inherited.
  382.         //
  383.         internal Hashtable SectionFactories {
  384.             get {
  385.                 if (_sectionFactories == null) {
  386.                     _sectionFactories = GetAllFactories(false);
  387.                 }
  388.                
  389.                 return _sectionFactories;
  390.             }
  391.         }
  392.        
  393.         //
  394.         // Collection of all section groups, both in this file and inherited.
  395.         //
  396.         internal Hashtable SectionGroupFactories {
  397.             get {
  398.                 if (_sectionGroupFactories == null) {
  399.                     _sectionGroupFactories = GetAllFactories(true);
  400.                 }
  401.                
  402.                 return _sectionGroupFactories;
  403.             }
  404.         }
  405.        
  406.         //
  407.         // Get all the factories available, both in this file and inherited.
  408.         //
  409.         private Hashtable GetAllFactories(bool isGroup)
  410.         {
  411.             Hashtable factories = new Hashtable();
  412.            
  413.             MgmtConfigurationRecord configRecord = this;
  414.             do {
  415.                 if (configRecord._factoryRecords != null) {
  416.                     foreach (FactoryRecord factoryRecord in configRecord._factoryRecords.Values) {
  417.                         if (factoryRecord.IsGroup == isGroup) {
  418.                             string configKey = factoryRecord.ConfigKey;
  419.                             factories[configKey] = new FactoryId(factoryRecord.ConfigKey, factoryRecord.Group, factoryRecord.Name);
  420.                         }
  421.                     }
  422.                 }
  423.                
  424.                 configRecord = configRecord.MgmtParent;
  425.             }
  426.             while (!configRecord.IsRootConfig);
  427.            
  428.             return factories;
  429.         }
  430.        
  431.         internal ConfigurationSection FindImmediateParentSection(ConfigurationSection section)
  432.         {
  433.             ConfigurationSection result = null;
  434.            
  435.             string configKey = section.SectionInformation.SectionName;
  436.             SectionRecord sectionRecord = GetSectionRecord(configKey, false);
  437.             if (sectionRecord.HasLocationInputs) {
  438.                 SectionInput input = sectionRecord.LastLocationInput;
  439.                 Debug.Assert(input.HasResult, "input.HasResult");
  440.                 result = (ConfigurationSection)input.Result;
  441.             }
  442.             else if (IsRootDeclaration(configKey, true)) {
  443.                 FactoryRecord factoryRecord = GetFactoryRecord(configKey, false);
  444.                
  445.                 object resultObject;
  446.                 object resultRuntimeObject;
  447.                 CreateSectionDefault(configKey, false, factoryRecord, null, out resultObject, out resultRuntimeObject);
  448.                 result = (ConfigurationSection)resultObject;
  449.             }
  450.             else {
  451.                 MgmtConfigurationRecord current = this.MgmtParent;
  452.                 while (!current.IsRootConfig) {
  453.                     sectionRecord = current.GetSectionRecord(configKey, false);
  454.                     if (sectionRecord != null && sectionRecord.HasResult) {
  455.                         result = (ConfigurationSection)sectionRecord.Result;
  456.                         break;
  457.                     }
  458.                    
  459.                     current = current.MgmtParent;
  460.                 }
  461.                
  462.                 Debug.Assert(!current.IsRootConfig, "An immediate parent result should have been found");
  463.             }
  464.            
  465.             if (!result.IsReadOnly()) {
  466.                 result.SetReadOnly();
  467.             }
  468.            
  469.             return result;
  470.         }
  471.        
  472.         //
  473.         // Get the immediate parent configuration section, and clone it.
  474.         //
  475.         internal ConfigurationSection FindAndCloneImmediateParentSection(ConfigurationSection configSection)
  476.         {
  477.             string configKey = configSection.SectionInformation.ConfigKey;
  478.             ConfigurationSection parentSection = FindImmediateParentSection(configSection);
  479.             SectionRecord sectionRecord = GetSectionRecord(configKey, false);
  480.             ConfigurationSection clone = (ConfigurationSection)UseParentResult(configKey, parentSection, sectionRecord);
  481.             return clone;
  482.         }
  483.        
  484.         //
  485.         // Revert the ConfigurationSection to the value of its parent.
  486.         //
  487.         internal void RevertToParent(ConfigurationSection configSection)
  488.         {
  489.            
  490.             // Remove any RawXml set by ConfigurationSection.SetRawXml
  491.             configSection.SectionInformation.RawXml = null;
  492.            
  493.             try {
  494.                 // Reset to parent value
  495.                 ConfigurationSection parentConfigSection = FindImmediateParentSection(configSection);
  496.                 configSection.Reset(parentConfigSection);
  497.                
  498.                 configSection.ResetModified();
  499.             }
  500.             catch (Exception e) {
  501.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_exception_in_config_section_handler, configSection.SectionInformation.SectionName), e, ConfigStreamInfo.StreamName, 0);
  502.             }
  503.             catch {
  504.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_exception_in_config_section_handler, configSection.SectionInformation.SectionName), null, ConfigStreamInfo.StreamName, 0);
  505.             }
  506.            
  507.             // Record that the section is to be removed.
  508.             configSection.SectionInformation.Removed = true;
  509.         }
  510.        
  511.         //
  512.         // Return the outer XML of a section as a string.
  513.         // Return null if the section does not exist in the file.
  514.         //
  515.         internal string GetRawXml(string configKey)
  516.         {
  517.             // Get the section record created during Init
  518.             SectionRecord sectionRecord = GetSectionRecord(configKey, false);
  519.             if (sectionRecord == null || !sectionRecord.HasFileInput) {
  520.                 return null;
  521.             }
  522.            
  523.             // The section exists, so find and return its RawXml.
  524.             string[] keys = configKey.Split(ConfigPathSeparatorParams);
  525.             ConfigXmlReader reader = GetSectionXmlReader(keys, sectionRecord.FileInput);
  526.            
  527.             return reader.RawXml;
  528.         }
  529.        
  530.         //
  531.         // Update the section with the XML provided.
  532.         //
  533.         // This method will throw out any changes made to the section up to this point.
  534.         //
  535.         // If xmlElement is null or empty, it is equivalent to calling RevertToParent
  536.         //
  537.         internal void SetRawXml(ConfigurationSection configSection, string xmlElement)
  538.         {
  539.            
  540.             // Null or empty is equivalent to RevertToParent().
  541.             if (string.IsNullOrEmpty(xmlElement)) {
  542.                 RevertToParent(configSection);
  543.                 return;
  544.             }
  545.            
  546.             ValidateSectionXml(xmlElement, configSection.SectionInformation.Name);
  547.            
  548.             // Reset the ConfigurationSection with the XML.
  549.             ConfigurationSection parentConfigSection = FindImmediateParentSection(configSection);
  550.             ConfigXmlReader reader = new ConfigXmlReader(xmlElement, null, 0);
  551.            
  552.             // Store the raw XML.
  553.             configSection.SectionInformation.RawXml = xmlElement;
  554.            
  555.             // Update the section with the xml
  556.             try {
  557.                 try {
  558.                     bool wasPresent = configSection.ElementPresent;
  559.                     PropertySourceInfo saveInfo = configSection.ElementInformation.PropertyInfoInternal();
  560.                    
  561.                     configSection.Reset(parentConfigSection);
  562.                     configSection.DeserializeSection(reader);
  563.                     configSection.ResetModified();
  564.                    
  565.                     configSection.ElementPresent = wasPresent;
  566.                     configSection.ElementInformation.ChangeSourceAndLineNumber(saveInfo);
  567.                 }
  568.                 catch {
  569.                     configSection.SectionInformation.RawXml = null;
  570.                     throw;
  571.                 }
  572.             }
  573.             catch (Exception e) {
  574.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_exception_in_config_section_handler, configSection.SectionInformation.SectionName), e, null, 0);
  575.             }
  576.             catch {
  577.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_exception_in_config_section_handler, configSection.SectionInformation.SectionName), null, null, 0);
  578.             }
  579.            
  580.             // Ignore previous attempts to remove the section.
  581.             configSection.SectionInformation.Removed = false;
  582.         }
  583.        
  584.         //
  585.         // Return true if a stream is being used by a configSource directive in other input.
  586.         //
  587.         private bool IsStreamUsed(string oldStreamName)
  588.         {
  589.             MgmtConfigurationRecord current = this;
  590.             if (IsLocationConfig) {
  591.                 //
  592.                 // For a location configuration, the input we need to check
  593.                 // are the section records and location sections in the file,
  594.                 // which are available in the parent record.
  595.                 //
  596.                 current = MgmtParent;
  597.                
  598.                 //
  599.                 // Check whether a file section is using the configsource directive.
  600.                 //
  601.                 if (current._sectionRecords != null) {
  602.                     foreach (SectionRecord sectionRecord in current._sectionRecords.Values) {
  603.                         if (sectionRecord.HasFileInput && StringUtil.EqualsIgnoreCase(sectionRecord.FileInput.SectionXmlInfo.ConfigSourceStreamName, oldStreamName)) {
  604.                             return true;
  605.                         }
  606.                     }
  607.                 }
  608.             }
  609.            
  610.             //
  611.             // Check whether a location is using the configsource directive.
  612.             //
  613.             if (current._locationSections != null) {
  614.                 foreach (LocationSectionRecord locationSectionRecord in current._locationSections) {
  615.                     if (StringUtil.EqualsIgnoreCase(locationSectionRecord.SectionXmlInfo.ConfigSourceStreamName, oldStreamName)) {
  616.                         return true;
  617.                     }
  618.                 }
  619.             }
  620.            
  621.             return false;
  622.         }
  623.        
  624.         //
  625.         // Set the configSource attribute on a ConfigurationSection
  626.         //
  627.         internal void ChangeConfigSource(SectionInformation sectionInformation, string oldConfigSource, string oldConfigSourceStreamName, string newConfigSource)
  628.         {
  629.            
  630.             if (String.IsNullOrEmpty(oldConfigSource)) {
  631.                 oldConfigSource = null;
  632.             }
  633.            
  634.             if (String.IsNullOrEmpty(newConfigSource)) {
  635.                 newConfigSource = null;
  636.             }
  637.            
  638.             // Check if there is a change to config source
  639.             if (StringUtil.EqualsIgnoreCase(oldConfigSource, newConfigSource))
  640.                 return;
  641.            
  642.             if (String.IsNullOrEmpty(ConfigStreamInfo.StreamName)) {
  643.                 throw new ConfigurationErrorsException(SR.GetString(SR.Config_source_requires_file));
  644.             }
  645.            
  646.             string newConfigSourceStreamName = null;
  647.             if (newConfigSource != null) {
  648.                 newConfigSourceStreamName = Host.GetStreamNameForConfigSource(ConfigStreamInfo.StreamName, newConfigSource);
  649.             }
  650.            
  651.             // Add the stream to the updates
  652.             if (newConfigSourceStreamName != null) {
  653.                 //
  654.                 // Ensure that no parent is using the same config source stream
  655.                 //
  656.                 ValidateUniqueChildConfigSource(sectionInformation.ConfigKey, newConfigSourceStreamName, newConfigSource, null);
  657.                
  658.                 StreamInfo streamInfo = (StreamInfo)_streamInfoUpdates[newConfigSourceStreamName];
  659.                 if (streamInfo != null) {
  660.                     //
  661.                     // Detect if another section in this file is using the same configSource
  662.                     // with has a different section name.
  663.                     //
  664.                     if (streamInfo.SectionName != sectionInformation.ConfigKey) {
  665.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_source_cannot_be_shared, newConfigSource));
  666.                     }
  667.                 }
  668.                 else {
  669.                     //
  670.                     // Add stream to updates
  671.                     //
  672.                     streamInfo = new StreamInfo(sectionInformation.ConfigKey, newConfigSource, newConfigSourceStreamName);
  673.                     _streamInfoUpdates.Add(newConfigSourceStreamName, streamInfo);
  674.                 }
  675.             }
  676.            
  677.             // remove old streamname if no longer referenced
  678.             if (oldConfigSourceStreamName != null && !IsStreamUsed(oldConfigSourceStreamName)) {
  679.                 _streamInfoUpdates.Remove(oldConfigSourceStreamName);
  680.             }
  681.            
  682.             // update the configSourceStreamName
  683.             sectionInformation.ConfigSourceStreamName = newConfigSourceStreamName;
  684.         }
  685.        
  686.         //
  687.         // Verify that the string is valid xml, begins with the expected section name,
  688.         // and contains no more or less than a single element.
  689.         //
  690.         // Throws a ConfigurationErrorsException if there is an error.
  691.         //
  692.         private void ValidateSectionXml(string xmlElement, string configKey)
  693.         {
  694.             if (string.IsNullOrEmpty(xmlElement))
  695.                 return;
  696.            
  697.             XmlTextReader reader = null;
  698.             try {
  699.                 XmlParserContext context = new XmlParserContext(null, null, null, XmlSpace.Default, Encoding.Unicode);
  700.                 reader = new XmlTextReader(xmlElement, XmlNodeType.Element, context);
  701.                
  702.                 // Verify that the it is an element
  703.                 reader.Read();
  704.                 if (reader.NodeType != XmlNodeType.Element) {
  705.                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_unexpected_node_type, reader.NodeType));
  706.                 }
  707.                
  708.                 // Verify the name of the element is a section
  709.                 string group;
  710.                 string name;
  711.                 SplitConfigKey(configKey, out group, out name);
  712.                 if (reader.Name != name) {
  713.                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_unexpected_element_name, reader.Name));
  714.                 }
  715.                
  716.                 for (;;) {
  717.                     if (!reader.Read()) {
  718.                         // ensure there is a matching end element
  719.                         if (reader.Depth != 0) {
  720.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_unexpected_element_end), reader);
  721.                         }
  722.                        
  723.                         break;
  724.                     }
  725.                    
  726.                     switch (reader.NodeType) {
  727.                         case XmlNodeType.XmlDeclaration:
  728.                         case XmlNodeType.DocumentType:
  729.                             // disallowed node types within a section
  730.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_invalid_node_type), reader);
  731.                             break;
  732.                         default:
  733.                            
  734.                             break;
  735.                     }
  736.                    
  737.                    
  738.                     // don't allow XML after the end element
  739.                     if (reader.Depth <= 0 && reader.NodeType != XmlNodeType.EndElement) {
  740.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_more_data_than_expected), reader);
  741.                     }
  742.                 }
  743.             }
  744.             finally {
  745.                 if (reader != null) {
  746.                     reader.Close();
  747.                 }
  748.             }
  749.         }
  750.        
  751.         //
  752.         // Add a new configuration section to this config file.
  753.         // This adds both the section declaration and definition to the config file.
  754.         //
  755.         // Called from ConfigurationSectionCollection.Add().
  756.         // Note this method DOES NOT update the associated ConfigurationSectionCollection.
  757.         //
  758.         internal void AddConfigurationSection(string group, string name, ConfigurationSection configSection)
  759.         {
  760.            
  761.             // <configSections> is not permitted within a <location> tag.
  762.             if (IsLocationConfig) {
  763.                 throw new InvalidOperationException(SR.GetString(SR.Config_add_configurationsection_in_location_config));
  764.             }
  765.            
  766.             VerifySectionName(name, null, false);
  767.            
  768.             if (configSection == null) {
  769.                 throw new ArgumentNullException("configSection");
  770.             }
  771.            
  772.             // Ensure the section is not already part of the configuration hierarchy.
  773.             if (configSection.SectionInformation.Attached) {
  774.                 throw new InvalidOperationException(SR.GetString(SR.Config_add_configurationsection_already_added));
  775.             }
  776.            
  777.             string configKey = BaseConfigurationRecord.CombineConfigKey(group, name);
  778.            
  779.             // Ensure the section is not already declared.
  780.             FactoryRecord factoryRecord = FindFactoryRecord(configKey, true);
  781.             if (factoryRecord != null) {
  782.                 throw new ArgumentException(SR.GetString(SR.Config_add_configurationsection_already_exists));
  783.             }
  784.            
  785.             // Add the configSource if needed.
  786.             if (!String.IsNullOrEmpty(configSection.SectionInformation.ConfigSource)) {
  787.                 ChangeConfigSource(configSection.SectionInformation, null, null, configSection.SectionInformation.ConfigSource);
  788.             }
  789.            
  790.             // Add to list of all sections.
  791.             if (_sectionFactories != null) {
  792.                 _sectionFactories.Add(configKey, new FactoryId(configKey, group, name));
  793.             }
  794.            
  795.             // Get the type name.
  796.             string typeName = configSection.SectionInformation.Type;
  797.             if (typeName == null) {
  798.                 typeName = Host.GetConfigTypeName(configSection.GetType());
  799.             }
  800.            
  801.             // Add a factory record for the section.
  802.             factoryRecord = new FactoryRecord(configKey, group, name, typeName, configSection.SectionInformation.AllowLocation, configSection.SectionInformation.AllowDefinition, configSection.SectionInformation.AllowExeDefinition, configSection.SectionInformation.RestartOnExternalChanges, configSection.SectionInformation.RequirePermission, _flags[IsTrusted],
  803.                 // isUndeclared
  804.             false, ConfigStreamInfo.StreamName, -1);
  805.            
  806.             // Construct a factory for the section
  807.             factoryRecord.Factory = TypeUtil.GetConstructorWithReflectionPermission(configSection.GetType(), typeof(ConfigurationSection), true);
  808.            
  809.             factoryRecord.IsFactoryTrustedWithoutAptca = TypeUtil.IsTypeFromTrustedAssemblyWithoutAptca(configSection.GetType());
  810.            
  811.             EnsureFactories()[configKey] = factoryRecord;
  812.            
  813.             // Add a section record for the section.
  814.             // Since we are adding a new definition, it cannot be locked.
  815.             SectionRecord sectionRecord = EnsureSectionRecordUnsafe(configKey, false);
  816.             sectionRecord.Result = configSection;
  817.             sectionRecord.ResultRuntimeObject = configSection;
  818.            
  819.             // Undo any previous removals of the section.
  820.             if (_removedSections != null) {
  821.                 _removedSections.Remove(configKey);
  822.             }
  823.            
  824.             // Attach the section to the configuration record.
  825.             configSection.SectionInformation.AttachToConfigurationRecord(this, factoryRecord, sectionRecord);
  826.            
  827.             //
  828.             // If there is rawXml, set it now. Note this will override any other changes to the section
  829.             // definition made after the call to SetXml.
  830.             //
  831.             string rawXml = configSection.SectionInformation.RawXml;
  832.             if (!String.IsNullOrEmpty(rawXml)) {
  833.                 configSection.SectionInformation.RawXml = null;
  834.                 configSection.SectionInformation.SetRawXml(rawXml);
  835.             }
  836.         }
  837.        
  838.         //
  839.         // Remove a configuration section from this config file.
  840.         // This removes both the section declaration and definition from the config file.
  841.         // Note, however, that if a parent config file declares the section,
  842.         // a new instance of the section can be retrieved having the value of the
  843.         // immediate parent.
  844.         //
  845.         // Called from ConfigurationSectionCollection.Remove().
  846.         // Note this method DOES NOT update the associated ConfigurationSectionCollection.
  847.         //
  848.         internal void RemoveConfigurationSection(string group, string name)
  849.         {
  850.             bool sectionIsUsed = false;
  851.             // Is section used in our record
  852.             VerifySectionName(name, null, true);
  853.            
  854.             string configKey = BaseConfigurationRecord.CombineConfigKey(group, name);
  855.            
  856.             // If it's already removed, don't try to remove it again.
  857.             if (RemovedSections.Contains(configKey)) {
  858.                 return;
  859.             }
  860.            
  861.             // If it's not a registered section, there's nothing to do.
  862.             if (FindFactoryRecord(configKey, true) == null) {
  863.                 return;
  864.             }
  865.            
  866.             // Detach from this record
  867.             ConfigurationSection configSection = GetConfigSection(configKey);
  868.             if (configSection != null) {
  869.                 configSection.SectionInformation.DetachFromConfigurationRecord();
  870.             }
  871.            
  872.             // Remove from list of all sections if this is the root declaration.
  873.             bool isRootDeclaration = IsRootDeclaration(configKey, false);
  874.             if (_sectionFactories != null && isRootDeclaration) {
  875.                 _sectionFactories.Remove(configKey);
  876.             }
  877.            
  878.             // Remove from collection of factory records.
  879.             if (!IsLocationConfig && _factoryRecords != null && _factoryRecords.Contains(configKey)) {
  880.                 sectionIsUsed = true;
  881.                 _factoryRecords.Remove(configKey);
  882.             }
  883.            
  884.             // Remove from collection of section records.
  885.             if (_sectionRecords != null && _sectionRecords.Contains(configKey)) {
  886.                 sectionIsUsed = true;
  887.                 _sectionRecords.Remove(configKey);
  888.             }
  889.            
  890.             // Remove all location section records for this section in this file.
  891.             if (_locationSections != null) {
  892.                 int i = 0;
  893.                 while (i < _locationSections.Count) {
  894.                     LocationSectionRecord locationSectionRecord = (LocationSectionRecord)_locationSections[i];
  895.                     if (locationSectionRecord.ConfigKey != configKey) {
  896.                         i++;
  897.                     }
  898.                     else {
  899.                         sectionIsUsed = true;
  900.                         _locationSections.RemoveAt(i);
  901.                     }
  902.                 }
  903.             }
  904.            
  905.             if (sectionIsUsed) {
  906.                 // Add to RemovedSections since we need to remove
  907.                 // it from the file later.
  908.                 RemovedSections.Add(configKey, configKey);
  909.             }
  910.            
  911.             //
  912.             // Remove all references from configSource
  913.             // Note that we can't remove an item while enumerating it.
  914.             //
  915.             List<string> streamsToRemove = new List<string>();
  916.             foreach (StreamInfo streamInfo in _streamInfoUpdates.Values) {
  917.                 if (streamInfo.SectionName == configKey) {
  918.                     streamsToRemove.Add(streamInfo.StreamName);
  919.                 }
  920.             }
  921.            
  922.             foreach (string stream in streamsToRemove) {
  923.                 _streamInfoUpdates.Remove(stream);
  924.             }
  925.         }
  926.        
  927.         //
  928.         // Add a new configuration section group to this config file.
  929.         //
  930.         // Called from ConfigurationSectionGroupCollection.Add().
  931.         // Note this method DOES NOT update the associated ConfigurationSectionGroupCollection.
  932.         //
  933.         internal void AddConfigurationSectionGroup(string group, string name, ConfigurationSectionGroup configSectionGroup)
  934.         {
  935.             // <location> tags can't have a <configSections> declaration.
  936.             if (IsLocationConfig) {
  937.                 throw new InvalidOperationException(SR.GetString(SR.Config_add_configurationsectiongroup_in_location_config));
  938.             }
  939.            
  940.             // Validate name argument.
  941.             VerifySectionName(name, null, false);
  942.            
  943.             // Validate configSectionGroup argument.
  944.             if (configSectionGroup == null) {
  945.                 throw ExceptionUtil.ParameterInvalid("name");
  946.             }
  947.            
  948.             // A section group can only belong to one section group collection.
  949.             if (configSectionGroup.Attached) {
  950.                 throw new InvalidOperationException(SR.GetString(SR.Config_add_configurationsectiongroup_already_added));
  951.             }
  952.            
  953.             string configKey = BaseConfigurationRecord.CombineConfigKey(group, name);
  954.            
  955.             // Do not add if the section group already exists, even if it is of a different type.
  956.             FactoryRecord factoryRecord = FindFactoryRecord(configKey, true);
  957.             if (factoryRecord != null) {
  958.                 throw new ArgumentException(SR.GetString(SR.Config_add_configurationsectiongroup_already_exists));
  959.             }
  960.            
  961.             // Add to list of all section groups.
  962.             if (_sectionGroupFactories != null) {
  963.                 _sectionGroupFactories.Add(configKey, new FactoryId(configKey, group, name));
  964.             }
  965.            
  966.             // Get the type name - if it is not specified explicitly, get it from the type of the object.
  967.             string typeName = configSectionGroup.Type;
  968.             if (typeName == null) {
  969.                 typeName = Host.GetConfigTypeName(configSectionGroup.GetType());
  970.             }
  971.            
  972.             // Create a factory record and add it to the collection of factory records.
  973.             factoryRecord = new FactoryRecord(configKey, group, name, typeName, ConfigStreamInfo.StreamName, -1);
  974.             EnsureFactories()[configKey] = factoryRecord;
  975.            
  976.             // Add it to list of evaluated configuration section groups.
  977.             SectionGroups[configKey] = configSectionGroup;
  978.            
  979.             // Remove it from RemovedSectionGroups if it was previously removed.
  980.             if (_removedSectionGroups != null) {
  981.                 _removedSectionGroups.Remove(configKey);
  982.             }
  983.            
  984.             // Attach to the configuration record.
  985.             configSectionGroup.AttachToConfigurationRecord(this, factoryRecord);
  986.         }
  987.        
  988.         //
  989.         // Return a list of all FactoryRecords of sections that are descendents of
  990.         // a section group.
  991.         //
  992.         private ArrayList GetDescendentSectionFactories(string configKey)
  993.         {
  994.             ArrayList sectionGroups = new ArrayList();
  995.            
  996.             string configKeyAncestor;
  997.             if (configKey.Length == 0) {
  998.                 configKeyAncestor = string.Empty;
  999.             }
  1000.             else {
  1001.                 configKeyAncestor = configKey + "/";
  1002.             }
  1003.            
  1004.             foreach (FactoryId factoryId in SectionFactories.Values) {
  1005.                 if (factoryId.Group == configKey || StringUtil.StartsWith(factoryId.Group, configKeyAncestor)) {
  1006.                     sectionGroups.Add(factoryId);
  1007.                 }
  1008.             }
  1009.            
  1010.             return sectionGroups;
  1011.         }
  1012.        
  1013.         //
  1014.         // Return a list of all FactoryRecords of section groups that are descendents of
  1015.         // a section group, including the section group itself.
  1016.         //
  1017.         private ArrayList GetDescendentSectionGroupFactories(string configKey)
  1018.         {
  1019.            
  1020.             ArrayList sectionGroups = new ArrayList();
  1021.            
  1022.             string configKeyAncestor;
  1023.             if (configKey.Length == 0) {
  1024.                 configKeyAncestor = string.Empty;
  1025.             }
  1026.             else {
  1027.                 configKeyAncestor = configKey + "/";
  1028.             }
  1029.            
  1030.             foreach (FactoryId factoryId in SectionGroupFactories.Values) {
  1031.                 if (factoryId.ConfigKey == configKey || StringUtil.StartsWith(factoryId.ConfigKey, configKeyAncestor)) {
  1032.                     sectionGroups.Add(factoryId);
  1033.                 }
  1034.             }
  1035.            
  1036.             return sectionGroups;
  1037.         }
  1038.        
  1039.         //
  1040.         // Remove a configuration section group from this config file.
  1041.         // This removes both the section group declaration and definition from the config file,
  1042.         // along with all descendent groups and sections.
  1043.         //
  1044.         // Note, however, that if a parent config file declares the section group,
  1045.         // a new instance of the section can be retrieved having the value of the
  1046.         // immediate parent.
  1047.         //
  1048.         // Called from ConfigurationSectionGroupCollection.Remove().
  1049.         // Note this method DOES NOT update the associated ConfigurationSectionCollection.
  1050.         //
  1051.         internal void RemoveConfigurationSectionGroup(string group, string name)
  1052.         {
  1053.             // Validate arguments
  1054.             VerifySectionName(name, null, false);
  1055.            
  1056.             string configKey = BaseConfigurationRecord.CombineConfigKey(group, name);
  1057.            
  1058.             // If it's not a registered section, there's nothing to do.
  1059.             if (FindFactoryRecord(configKey, true) == null) {
  1060.                 return;
  1061.             }
  1062.            
  1063.             // Remove all descendent sections.
  1064.             ArrayList sections = GetDescendentSectionFactories(configKey);
  1065.             foreach (FactoryId descendent in sections) {
  1066.                 RemoveConfigurationSection(descendent.Group, descendent.Name);
  1067.             }
  1068.            
  1069.             // Remove all descendent sections groups, including the configKey group.
  1070.             ArrayList sectionGroups = GetDescendentSectionGroupFactories(configKey);
  1071.             foreach (FactoryId descendent in sectionGroups) {
  1072.                 //
  1073.                 // If it's already removed, don't try to remove it again.
  1074.                 // We don't do this test above the loop for configKey, because
  1075.                 // the section groups contained within the section group may
  1076.                 // be changed by the user once added.
  1077.                 //
  1078.                 if (RemovedSectionGroups.Contains(descendent.ConfigKey)) {
  1079.                     continue;
  1080.                 }
  1081.                
  1082.                 // If the section group has been evaluated, detatch it.
  1083.                 ConfigurationSectionGroup sectionGroup = LookupSectionGroup(descendent.ConfigKey);
  1084.                 if (sectionGroup != null) {
  1085.                     sectionGroup.DetachFromConfigurationRecord();
  1086.                 }
  1087.                
  1088.                 // Remove from list of all section group factories if this is the root declaration.
  1089.                 bool isRootDeclaration = IsRootDeclaration(descendent.ConfigKey, false);
  1090.                 if (_sectionGroupFactories != null && isRootDeclaration) {
  1091.                     _sectionGroupFactories.Remove(descendent.ConfigKey);
  1092.                 }
  1093.                
  1094.                 // Remove from list of factory records.
  1095.                 if (!IsLocationConfig && _factoryRecords != null) {
  1096.                     _factoryRecords.Remove(descendent.ConfigKey);
  1097.                 }
  1098.                
  1099.                 // Remove from evaluated section groups.
  1100.                 if (_sectionGroups != null) {
  1101.                     _sectionGroups.Remove(descendent.ConfigKey);
  1102.                 }
  1103.                
  1104.                 //
  1105.                 // Add to list of section groups that are removed
  1106.                 // Note that this will add section groups that might not be used
  1107.                 // in this config file. That just results in some extra work during
  1108.                 // save, it is not harmful.
  1109.                 //
  1110.                 RemovedSectionGroups.Add(descendent.ConfigKey, descendent.ConfigKey);
  1111.             }
  1112.         }
  1113.        
  1114.         //
  1115.         // Return the file path to this configuration file.
  1116.         //
  1117.         internal string ConfigurationFilePath {
  1118.             get {
  1119.                 string filepath = UpdateConfigHost.GetNewStreamname(ConfigStreamInfo.StreamName);
  1120.                 if (filepath == null) {
  1121.                     filepath = String.Empty;
  1122.                 }
  1123.                
  1124.                 if (!String.IsNullOrEmpty(filepath)) {
  1125.                     new FileIOPermission(FileIOPermissionAccess.PathDiscovery, filepath).Demand();
  1126.                 }
  1127.                
  1128.                 return filepath;
  1129.             }
  1130.         }
  1131.        
  1132.         //
  1133.         // Update the config file with the changes in each ConfigurationSection
  1134.         //
  1135.         internal void SaveAs(string filename, ConfigurationSaveMode saveMode, bool forceUpdateAll)
  1136.         {
  1137.            
  1138.             // Get the updates.
  1139.             SectionUpdates declarationUpdates = GetConfigDeclarationUpdates(saveMode, forceUpdateAll);
  1140.            
  1141.             ConfigDefinitionUpdates definitionUpdates;
  1142.             ArrayList configSourceUpdates;
  1143.             bool checkedConfigForUpdates = false;
  1144.             bool requireUpdates = (filename != null);
  1145.             GetConfigDefinitionUpdates(requireUpdates, saveMode, forceUpdateAll, out definitionUpdates, out configSourceUpdates);
  1146.            
  1147.             if (filename != null) {
  1148.                 Debug.Assert(filename.Length > 0, "The caller should make sure that filename is not empty");
  1149.                
  1150.                 //
  1151.                 // Verify that the filename is not being used.
  1152.                 //
  1153.                 // Note that if we are using a remote host, all the streamName's in _streamInfoUpdates
  1154.                 // are actually fullpaths on the remote machine. In this case there is no way to
  1155.                 // detect if we have a conflict or not.
  1156.                 if (!Host.IsRemote && _streamInfoUpdates.Contains(filename)) {
  1157.                     throw new ArgumentException(SR.GetString(SR.Filename_in_SaveAs_is_used_already, filename));
  1158.                 }
  1159.                
  1160.                 //
  1161.                 // If there was no config file for this config record,
  1162.                 // record the new stream name and version.
  1163.                 //
  1164.                 if (String.IsNullOrEmpty(ConfigStreamInfo.StreamName)) {
  1165.                     StreamInfo streamInfo = new StreamInfo(null, null, filename);
  1166.                     _streamInfoUpdates.Add(filename, streamInfo);
  1167.                    
  1168.                     ConfigStreamInfo.StreamName = filename;
  1169.                     ConfigStreamInfo.StreamVersion = MonitorStream(null, null, ConfigStreamInfo.StreamName);
  1170.                 }
  1171.                
  1172.                 //
  1173.                 // Update the host to redirect filenames
  1174.                 //
  1175.                 UpdateConfigHost.AddStreamname(ConfigStreamInfo.StreamName, filename, Host.IsRemote);
  1176.                
  1177.                 // Redirect also all configSource filenames
  1178.                 foreach (StreamInfo streamInfo in _streamInfoUpdates.Values) {
  1179.                     if (!String.IsNullOrEmpty(streamInfo.SectionName)) {
  1180.                         // Get the new configSource streamName based on the new filename path
  1181.                         string newStreamName = InternalConfigHost.StaticGetStreamNameForConfigSource(filename, streamInfo.ConfigSource);
  1182.                        
  1183.                         // Ask UpdateConfigHost to intercept them.
  1184.                         UpdateConfigHost.AddStreamname(streamInfo.StreamName, newStreamName, Host.IsRemote);
  1185.                     }
  1186.                 }
  1187.             }
  1188.            
  1189.             if (!requireUpdates) {
  1190.                 // Check if there are any updates needed for the
  1191.                 // configuration record itself.
  1192.                 requireUpdates = RecordItselfRequiresUpdates;
  1193.             }
  1194.            
  1195.             if (declarationUpdates != null || definitionUpdates != null || requireUpdates) {
  1196.                 // Copy the input stream before opening the output stream.
  1197.                 byte[] readBuffer = null;
  1198.                 if (ConfigStreamInfo.HasStream) {
  1199.                     using (Stream streamRead = Host.OpenStreamForRead(ConfigStreamInfo.StreamName)) {
  1200.                         if (streamRead == null) {
  1201.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_file_has_changed), ConfigStreamInfo.StreamName, 0);
  1202.                         }
  1203.                        
  1204.                         readBuffer = new byte[streamRead.Length];
  1205.                         int count = streamRead.Read(readBuffer, 0, (int)streamRead.Length);
  1206.                         if (count != streamRead.Length) {
  1207.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_data_read_count_mismatch));
  1208.                         }
  1209.                     }
  1210.                 }
  1211.                
  1212.                 string changedStreamName = FindChangedConfigurationStream();
  1213.                 if (changedStreamName != null) {
  1214.                     throw new ConfigurationErrorsException(SR.GetString(SR.Config_file_has_changed), changedStreamName, 0);
  1215.                 }
  1216.                
  1217.                 checkedConfigForUpdates = true;
  1218.                
  1219.                 // Write the changes to the output stream.
  1220.                 object writeContext = null;
  1221.                 bool streamOpened = false;
  1222.                 try {
  1223.                     try {
  1224.                         using (Stream streamWrite = Host.OpenStreamForWrite(ConfigStreamInfo.StreamName, null, ref writeContext)) {
  1225.                             streamOpened = true;
  1226.                             using (StreamWriter streamWriter = new StreamWriter(streamWrite)) {
  1227.                                 XmlUtilWriter utilWriter = new XmlUtilWriter(streamWriter, true);
  1228.                                 if (ConfigStreamInfo.HasStream) {
  1229.                                     CopyConfig(declarationUpdates, definitionUpdates, readBuffer, ConfigStreamInfo.StreamName, NamespaceChangeNeeded, utilWriter);
  1230.                                 }
  1231.                                 else {
  1232.                                     CreateNewConfig(declarationUpdates, definitionUpdates, NamespaceChangeNeeded, utilWriter);
  1233.                                 }
  1234.                             }
  1235.                         }
  1236.                     }
  1237.                     catch {
  1238.                         if (streamOpened) {
  1239.                             Host.WriteCompleted(ConfigStreamInfo.StreamName, false, writeContext);
  1240.                         }
  1241.                        
  1242.                         throw;
  1243.                     }
  1244.                 }
  1245.                 //
  1246.                 // Guarantee that exceptions contain at least the name of the stream by wrapping them
  1247.                 // in a ConfigurationException.
  1248.                 //
  1249.                 catch (Exception e) {
  1250.                     throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), e, ConfigStreamInfo.StreamName, 0);
  1251.                 }
  1252.                 catch {
  1253.                     throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), null, ConfigStreamInfo.StreamName, 0);
  1254.                 }
  1255.                
  1256.                 Host.WriteCompleted(ConfigStreamInfo.StreamName, true, writeContext);
  1257.                
  1258.                 // Update stream information for the config file
  1259.                 ConfigStreamInfo.HasStream = true;
  1260.                 ConfigStreamInfo.ClearStreamInfos();
  1261.                 ConfigStreamInfo.StreamVersion = MonitorStream(null, null, ConfigStreamInfo.StreamName);
  1262.             }
  1263.            
  1264.             if (configSourceUpdates != null) {
  1265.                 // If we haven't checked before, check now
  1266.                 if (!checkedConfigForUpdates) {
  1267.                     string changedStreamName = FindChangedConfigurationStream();
  1268.                     if (changedStreamName != null) {
  1269.                         throw new ConfigurationErrorsException(SR.GetString(SR.Config_file_has_changed), changedStreamName, 0);
  1270.                     }
  1271.                 }
  1272.                
  1273.                 // write updates
  1274.                 foreach (DefinitionUpdate update in configSourceUpdates) {
  1275.                     SaveConfigSource(update);
  1276.                 }
  1277.             }
  1278.            
  1279.             // Update state to reflect the changes to the config file
  1280.             UpdateRecords();
  1281.         }
  1282.        
  1283.         private bool AreDeclarationAttributesModified(FactoryRecord factoryRecord, ConfigurationSection configSection)
  1284.         {
  1285.             return factoryRecord.FactoryTypeName != configSection.SectionInformation.Type || factoryRecord.AllowLocation != configSection.SectionInformation.AllowLocation || factoryRecord.RestartOnExternalChanges != configSection.SectionInformation.RestartOnExternalChanges || factoryRecord.RequirePermission != configSection.SectionInformation.RequirePermission || factoryRecord.AllowDefinition != configSection.SectionInformation.AllowDefinition || factoryRecord.AllowExeDefinition != configSection.SectionInformation.AllowExeDefinition || configSection.SectionInformation.IsModifiedFlags();
  1286.         }
  1287.        
  1288.         private void AppendAttribute(StringBuilder sb, string key, string value)
  1289.         {
  1290.             sb.Append(key);
  1291.             sb.Append("=\"");
  1292.             sb.Append(value);
  1293.             sb.Append("\" ");
  1294.         }
  1295.        
  1296.         private string GetUpdatedSectionDeclarationXml(FactoryRecord factoryRecord, ConfigurationSection configSection, ConfigurationSaveMode saveMode)
  1297.         {
  1298.             StringBuilder sb = new StringBuilder();
  1299.             sb.Append('<');
  1300.             sb.Append(KEYWORD_SECTION);
  1301.             sb.Append(' ');
  1302.             AppendAttribute(sb, KEYWORD_SECTION_NAME, configSection.SectionInformation.Name);
  1303.             AppendAttribute(sb, KEYWORD_SECTION_TYPE, (configSection.SectionInformation.Type != null) ? configSection.SectionInformation.Type : factoryRecord.FactoryTypeName);
  1304.            
  1305.             if (!configSection.SectionInformation.AllowLocation || (saveMode == ConfigurationSaveMode.Full) || ((saveMode == ConfigurationSaveMode.Modified) && configSection.SectionInformation.AllowLocationModified)) {
  1306.                 AppendAttribute(sb, KEYWORD_SECTION_ALLOWLOCATION, configSection.SectionInformation.AllowLocation ? KEYWORD_TRUE : KEYWORD_FALSE);
  1307.             }
  1308.            
  1309.             if ((configSection.SectionInformation.AllowDefinition != ConfigurationAllowDefinition.Everywhere) || (saveMode == ConfigurationSaveMode.Full) || (saveMode == ConfigurationSaveMode.Modified && configSection.SectionInformation.AllowDefinitionModified)) {
  1310.                
  1311.                 string v = null;
  1312.                 switch (configSection.SectionInformation.AllowDefinition) {
  1313.                     case ConfigurationAllowDefinition.Everywhere:
  1314.                         v = KEYWORD_SECTION_ALLOWDEFINITION_EVERYWHERE;
  1315.                         break;
  1316.                     case ConfigurationAllowDefinition.MachineOnly:
  1317.                         v = KEYWORD_SECTION_ALLOWDEFINITION_MACHINEONLY;
  1318.                         break;
  1319.                     case ConfigurationAllowDefinition.MachineToWebRoot:
  1320.                        
  1321.                         v = KEYWORD_SECTION_ALLOWDEFINITION_MACHINETOWEBROOT;
  1322.                         break;
  1323.                     case ConfigurationAllowDefinition.MachineToApplication:
  1324.                        
  1325.                         v = KEYWORD_SECTION_ALLOWDEFINITION_MACHINETOAPPLICATION;
  1326.                         break;
  1327.                 }
  1328.                
  1329.                 AppendAttribute(sb, KEYWORD_SECTION_ALLOWDEFINITION, v);
  1330.             }
  1331.            
  1332.             if ((configSection.SectionInformation.AllowExeDefinition != ConfigurationAllowExeDefinition.MachineToApplication) || (saveMode == ConfigurationSaveMode.Full) || (saveMode == ConfigurationSaveMode.Modified && configSection.SectionInformation.AllowExeDefinitionModified)) {
  1333.                
  1334.                 AppendAttribute(sb, KEYWORD_SECTION_ALLOWEXEDEFINITION, ExeDefinitionToString(configSection.SectionInformation.AllowExeDefinition));
  1335.             }
  1336.            
  1337.             if (!configSection.SectionInformation.RestartOnExternalChanges) {
  1338.                 AppendAttribute(sb, KEYWORD_SECTION_RESTARTONEXTERNALCHANGES, KEYWORD_FALSE);
  1339.             }
  1340.             else if ((saveMode == ConfigurationSaveMode.Full) || (saveMode == ConfigurationSaveMode.Modified && configSection.SectionInformation.RestartOnExternalChangesModified)) {
  1341.                 AppendAttribute(sb, KEYWORD_SECTION_RESTARTONEXTERNALCHANGES, KEYWORD_TRUE);
  1342.             }
  1343.            
  1344.             if (!configSection.SectionInformation.RequirePermission) {
  1345.                 AppendAttribute(sb, KEYWORD_SECTION_REQUIREPERMISSION, KEYWORD_FALSE);
  1346.             }
  1347.             else if ((saveMode == ConfigurationSaveMode.Full) || (saveMode == ConfigurationSaveMode.Modified && configSection.SectionInformation.RequirePermissionModified)) {
  1348.                 AppendAttribute(sb, KEYWORD_SECTION_REQUIREPERMISSION, KEYWORD_TRUE);
  1349.             }
  1350.            
  1351.             sb.Append("/>");
  1352.            
  1353.             return sb.ToString();
  1354.         }
  1355.        
  1356.         // ExeDefinitionToString
  1357.         //
  1358.         // Take an ExeDefinition and translate it to a string
  1359.         //
  1360.         private string ExeDefinitionToString(ConfigurationAllowExeDefinition allowDefinition)
  1361.         {
  1362.             switch (allowDefinition) {
  1363.                 case ConfigurationAllowExeDefinition.MachineOnly:
  1364.                     return KEYWORD_SECTION_ALLOWDEFINITION_MACHINEONLY;
  1365.                 case ConfigurationAllowExeDefinition.MachineToApplication:
  1366.                    
  1367.                     return KEYWORD_SECTION_ALLOWDEFINITION_MACHINETOAPPLICATION;
  1368.                 case ConfigurationAllowExeDefinition.MachineToRoamingUser:
  1369.                    
  1370.                     return KEYWORD_SECTION_ALLOWEXEDEFINITION_MACHTOROAMING;
  1371.                 case ConfigurationAllowExeDefinition.MachineToLocalUser:
  1372.                    
  1373.                     return KEYWORD_SECTION_ALLOWEXEDEFINITION_MACHTOLOCAL;
  1374.             }
  1375.            
  1376.             throw ExceptionUtil.PropertyInvalid("AllowExeDefinition");
  1377.         }
  1378.        
  1379.         private string GetUpdatedSectionGroupDeclarationXml(FactoryRecord factoryRecord, ConfigurationSectionGroup configSectionGroup)
  1380.         {
  1381.             StringBuilder sb = new StringBuilder();
  1382.             sb.Append('<');
  1383.             sb.Append(KEYWORD_SECTIONGROUP);
  1384.             sb.Append(' ');
  1385.             AppendAttribute(sb, KEYWORD_SECTIONGROUP_NAME, configSectionGroup.Name);
  1386.             AppendAttribute(sb, KEYWORD_SECTIONGROUP_TYPE, (configSectionGroup.Type != null) ? configSectionGroup.Type : factoryRecord.FactoryTypeName);
  1387.            
  1388.             sb.Append('>');
  1389.            
  1390.             return sb.ToString();
  1391.         }
  1392.        
  1393.         private bool HasRemovedSectionsOrGroups {
  1394.             get { return (_removedSections != null && _removedSections.Count > 0) || (_removedSectionGroups != null && _removedSectionGroups.Count > 0); }
  1395.         }
  1396.        
  1397.         // HasRemovedSections
  1398.         //
  1399.         // Does this MgmtConfigrationRecord have any sections to be removed?
  1400.         //
  1401.         private bool HasRemovedSections {
  1402.             get { return ((_removedSections != null) && (_removedSections.Count > 0)); }
  1403.         }
  1404.        
  1405.         // Gather all the updates to the configuration section declarations.
  1406.         private SectionUpdates GetConfigDeclarationUpdates(ConfigurationSaveMode saveMode, bool forceUpdateAll)
  1407.         {
  1408.             if (IsLocationConfig)
  1409.                 return null;
  1410.            
  1411.             // hasChanged will be set to true if there is any change that will impact the current config file.
  1412.             bool hasChanged = HasRemovedSectionsOrGroups;
  1413.             SectionUpdates sectionUpdates = new SectionUpdates(string.Empty);
  1414.            
  1415.             if (_factoryRecords != null) {
  1416.                 foreach (FactoryRecord factoryRecord in _factoryRecords.Values) {
  1417.                     if (!factoryRecord.IsGroup) {
  1418.                         string updatedXml = null;
  1419.                        
  1420.                         // Never write out an undeclared section.
  1421.                         if (factoryRecord.IsUndeclared) {
  1422.                             continue;
  1423.                         }
  1424.                        
  1425.                         // Note that GetConfigSection will return only those sections that have a sectionRecord
  1426.                         // and has a result. In another word, only sections that have been accessed.
  1427.                         ConfigurationSection configSection = GetConfigSection(factoryRecord.ConfigKey);
  1428.                        
  1429.                         if (configSection != null) {
  1430.                            
  1431.                             // We should skip this section declaration only if all below hold true:
  1432.                             // 1. The section should not be declared at this level. Reasons:
  1433.                             // i. The section is originally not declared at this level, or
  1434.                             // ii. The user calls SectionInformation.ForceDeclaration(false)
  1435.                             // 2. It's not machine.config. Otherwise we must declare it even if the user called ForceDeclaration(false)
  1436.                             // 3. It's already declared higher up.
  1437.                             if (!configSection.SectionInformation.IsDeclared && !MgmtParent.IsRootConfig && MgmtParent.FindFactoryRecord(factoryRecord.ConfigKey, false) != null) {
  1438.                                
  1439.                                 if (factoryRecord.HasFile) {
  1440.                                     hasChanged = true;
  1441.                                 }
  1442.                                
  1443.                                 continue;
  1444.                             }
  1445.                            
  1446.                             if (AreDeclarationAttributesModified(factoryRecord, configSection) || !factoryRecord.HasFile) {
  1447.                                 hasChanged = true;
  1448.                                 updatedXml = GetUpdatedSectionDeclarationXml(factoryRecord, configSection, saveMode);
  1449.                             }
  1450.                         }
  1451.                        
  1452.                         DeclarationUpdate update = new DeclarationUpdate(factoryRecord.ConfigKey, !factoryRecord.HasFile, updatedXml);
  1453.                         sectionUpdates.AddSection(update);
  1454.                     }
  1455.                     else {
  1456.                         bool addGroupUpdate = false;
  1457.                        
  1458.                         // LookupSectionGroup will return an object only if the group has been accessed
  1459.                         ConfigurationSectionGroup configSectionGroup = LookupSectionGroup(factoryRecord.ConfigKey);
  1460.                        
  1461.                         if (!factoryRecord.HasFile) {
  1462.                             // Not in the file, so it means the group is added programmatically.
  1463.                             addGroupUpdate = true;
  1464.                         }
  1465.                         else if (configSectionGroup != null && configSectionGroup.IsDeclarationRequired) {
  1466.                             // The section group is declared in this config file
  1467.                             addGroupUpdate = true;
  1468.                         }
  1469.                         else if (factoryRecord.FactoryTypeName != null || configSectionGroup != null) {
  1470.                             FactoryRecord parentFactoryRecord = null;
  1471.                             if (!MgmtParent.IsRootConfig) {
  1472.                                 parentFactoryRecord = MgmtParent.FindFactoryRecord(factoryRecord.ConfigKey, false);
  1473.                             }
  1474.                            
  1475.                             // Add it if declaration is required. Please note this check is identical to the check
  1476.                             // for _declarationRequired in ConfigurationSectionGroup.AttachToConfigurationRecord.
  1477.                             addGroupUpdate = (parentFactoryRecord == null || parentFactoryRecord.FactoryTypeName == null);
  1478.                         }
  1479.                        
  1480.                         if (addGroupUpdate) {
  1481.                             string updatedXml = null;
  1482.                            
  1483.                             if (!factoryRecord.HasFile || (configSectionGroup != null && configSectionGroup.Type != factoryRecord.FactoryTypeName)) {
  1484.                                
  1485.                                 hasChanged = true;
  1486.                                 updatedXml = GetUpdatedSectionGroupDeclarationXml(factoryRecord, configSectionGroup);
  1487.                             }
  1488.                            
  1489.                             Debug.Assert(!factoryRecord.IsUndeclared, "!factoryRecord.IsUndeclared");
  1490.                             Debug.Assert(!IsImplicitSection(factoryRecord.ConfigKey), "We should never write out an implicit section");
  1491.                            
  1492.                             DeclarationUpdate update = new DeclarationUpdate(factoryRecord.ConfigKey, !factoryRecord.HasFile, updatedXml);
  1493.                             sectionUpdates.AddSectionGroup(update);
  1494.                         }
  1495.                     }
  1496.                 }
  1497.             }
  1498.            
  1499.             if (_sectionRecords != null) {
  1500.                 foreach (SectionRecord sectionRecord in _sectionRecords.Values) {
  1501.                     if (GetFactoryRecord(sectionRecord.ConfigKey, false) != null || !sectionRecord.HasResult) {
  1502.                         // Skip because this factory is defined locally ( in
  1503.                         // which case we handled above), or it was not used
  1504.                         continue;
  1505.                     }
  1506.                    
  1507.                     ConfigurationSection configSection = (ConfigurationSection)sectionRecord.Result;
  1508.                     FactoryRecord factoryRecord = MgmtParent.FindFactoryRecord(sectionRecord.ConfigKey, false);
  1509.                    
  1510.                     // Add this section declaration if:
  1511.                     // 1. The section is not declared locally (otherwise it's handled above)
  1512.                     // 2. SectionInformation.IsDeclared is true (i.e. user called SectionInformation.ForceDeclaration(true))
  1513.                     if (configSection.SectionInformation.IsDeclared) {
  1514.                         Debug.Assert(!IsImplicitSection(sectionRecord.ConfigKey), "We should never write out an implicit section");
  1515.                         Debug.Assert(!factoryRecord.IsUndeclared, "!factoryRecord.IsUndeclared");
  1516.                         hasChanged = true;
  1517.                         string updatedXml = GetUpdatedSectionDeclarationXml(factoryRecord, configSection, saveMode);
  1518.                         DeclarationUpdate update = new DeclarationUpdate(factoryRecord.ConfigKey, true, updatedXml);
  1519.                         sectionUpdates.AddSection(update);
  1520.                     }
  1521.                 }
  1522.             }
  1523.            
  1524.             if (_sectionGroups != null) {
  1525.                 foreach (ConfigurationSectionGroup configSectionGroup in _sectionGroups.Values) {
  1526.                     if (GetFactoryRecord(configSectionGroup.SectionGroupName, false) != null) {
  1527.                         continue;
  1528.                     }
  1529.                    
  1530.                     FactoryRecord factoryRecord = MgmtParent.FindFactoryRecord(configSectionGroup.SectionGroupName, false);
  1531.                     if (configSectionGroup.IsDeclared || (factoryRecord != null && configSectionGroup.Type != factoryRecord.FactoryTypeName)) {
  1532.                        
  1533.                         hasChanged = true;
  1534.                         string updatedXml = GetUpdatedSectionGroupDeclarationXml(factoryRecord, configSectionGroup);
  1535.                         DeclarationUpdate update = new DeclarationUpdate(factoryRecord.ConfigKey, true, updatedXml);
  1536.                         sectionUpdates.AddSectionGroup(update);
  1537.                     }
  1538.                 }
  1539.             }
  1540.            
  1541.             if (hasChanged) {
  1542.                 return sectionUpdates;
  1543.             }
  1544.             else {
  1545.                 return null;
  1546.             }
  1547.         }
  1548.        
  1549.         private bool AreLocationAttributesModified(SectionRecord sectionRecord, ConfigurationSection configSection)
  1550.         {
  1551.             bool allowOverride;
  1552.             bool inheritInChildApplications;
  1553.            
  1554.             if (sectionRecord.HasFileInput) {
  1555.                 SectionXmlInfo sectionXmlInfo = sectionRecord.FileInput.SectionXmlInfo;
  1556.                 allowOverride = !sectionXmlInfo.LockChildren;
  1557.                 inheritInChildApplications = !sectionXmlInfo.SkipInChildApps;
  1558.             }
  1559.             else {
  1560.                 allowOverride = true;
  1561.                 inheritInChildApplications = true;
  1562.             }
  1563.            
  1564.             return (allowOverride != configSection.SectionInformation.AllowOverride) || (inheritInChildApplications != configSection.SectionInformation.InheritInChildApplications);
  1565.         }
  1566.        
  1567.         private bool AreSectionAttributesModified(SectionRecord sectionRecord, ConfigurationSection configSection)
  1568.         {
  1569.             string configSource;
  1570.             string protectionProviderName;
  1571.            
  1572.             if (sectionRecord.HasFileInput) {
  1573.                 SectionXmlInfo sectionXmlInfo = sectionRecord.FileInput.SectionXmlInfo;
  1574.                 configSource = sectionXmlInfo.ConfigSource;
  1575.                 protectionProviderName = sectionXmlInfo.ProtectionProviderName;
  1576.             }
  1577.             else {
  1578.                 configSource = null;
  1579.                 protectionProviderName = null;
  1580.             }
  1581.            
  1582.             return !StringUtil.EqualsNE(configSource, configSection.SectionInformation.ConfigSource) || !StringUtil.EqualsNE(protectionProviderName, configSection.SectionInformation.ProtectionProviderName) || AreLocationAttributesModified(sectionRecord, configSection);
  1583.         }
  1584.        
  1585.         private bool IsConfigSectionMoved(SectionRecord sectionRecord, ConfigurationSection configSection)
  1586.         {
  1587.             if (!sectionRecord.HasFileInput)
  1588.                 return true;
  1589.            
  1590.             return AreLocationAttributesModified(sectionRecord, configSection);
  1591.         }
  1592.        
  1593.         // Gather all the updates to the configuration section definitions.
  1594.         private void GetConfigDefinitionUpdates(bool requireUpdates, ConfigurationSaveMode saveMode, bool forceSaveAll, out ConfigDefinitionUpdates definitionUpdates, out ArrayList configSourceUpdates)
  1595.         {
  1596.            
  1597.             definitionUpdates = new ConfigDefinitionUpdates();
  1598.             configSourceUpdates = null;
  1599.             bool hasChanged = HasRemovedSections;
  1600.            
  1601.             // Loop through all the section records.
  1602.             if (_sectionRecords != null) {
  1603.                 InitProtectedConfigurationSection();
  1604.                 // Make sure we have the initialized the protected config section, otherwise the foreach loop may blow up
  1605.                 foreach (DictionaryEntry de in _sectionRecords) {
  1606.                     string configKey = (string)de.Key;
  1607.                     SectionRecord sectionRecord = (SectionRecord)de.Value;
  1608.                     sectionRecord.AddUpdate = false;
  1609.                     bool addUpdate = sectionRecord.HasFileInput;
  1610.                     // If true, add this section to definitionUpdates, and optinally to configSourceUpdates
  1611.                     bool allowOverride = true;
  1612.                     bool inheritInChildApplications = true;
  1613.                     bool moved = false;
  1614.                     string updatedXml = null;
  1615.                     bool addToConfigSourceUpdates = false;
  1616.                     // If true, we have to update the external config file for this section
  1617.                     if (!sectionRecord.HasResult) {
  1618.                         if (sectionRecord.HasFileInput) {
  1619.                             SectionXmlInfo sectionXmlInfo = sectionRecord.FileInput.SectionXmlInfo;
  1620.                             allowOverride = !sectionXmlInfo.LockChildren;
  1621.                             inheritInChildApplications = !sectionXmlInfo.SkipInChildApps;
  1622.                             addToConfigSourceUpdates = requireUpdates && !String.IsNullOrEmpty(sectionXmlInfo.ConfigSource);
  1623.                         }
  1624.                     }
  1625.                     else {
  1626.                         ConfigurationSection configSection = (ConfigurationSection)sectionRecord.Result;
  1627.                        
  1628.                         allowOverride = configSection.SectionInformation.AllowOverride;
  1629.                         inheritInChildApplications = configSection.SectionInformation.InheritInChildApplications;
  1630.                        
  1631.                         // it is an error to require a location section when the type doesn't allow locations.
  1632.                         if (!configSection.SectionInformation.AllowLocation && (!allowOverride || !inheritInChildApplications)) {
  1633.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_inconsistent_location_attributes, configKey));
  1634.                         }
  1635.                        
  1636.                         addToConfigSourceUpdates = requireUpdates && !String.IsNullOrEmpty(configSection.SectionInformation.ConfigSource);
  1637.                         try {
  1638.                             bool isModified = configSection.SectionInformation.ForceSave || configSection.IsModified() || (forceSaveAll && !configSection.SectionInformation.IsLocked);
  1639.                            
  1640.                             bool sectionAttributesModified = AreSectionAttributesModified(sectionRecord, configSection);
  1641.                             bool sectionContentModified = (isModified || configSection.SectionInformation.RawXml != null);
  1642.                            
  1643.                             // Get the updated XML if the section has been modified.
  1644.                             if (sectionContentModified || sectionAttributesModified) {
  1645.                                 configSection.SectionInformation.VerifyIsEditable();
  1646.                                 configSection.SectionInformation.Removed = false;
  1647.                                 addUpdate = true;
  1648.                                 moved = IsConfigSectionMoved(sectionRecord, configSection);
  1649.                                
  1650.                                 if (!addToConfigSourceUpdates) {
  1651.                                     addToConfigSourceUpdates = !String.IsNullOrEmpty(configSection.SectionInformation.ConfigSource) && (sectionContentModified || configSection.SectionInformation.ConfigSourceModified);
  1652.                                 }
  1653.                                
  1654.                                 if (isModified || configSection.SectionInformation.RawXml == null || saveMode == ConfigurationSaveMode.Full) {
  1655.                                     // Note: we won't use RawXml if saveMode == Full because Full means we want to
  1656.                                     // write all properties, and RawXml may not have all properties.
  1657.                                     ConfigurationSection parentConfigSection = FindImmediateParentSection(configSection);
  1658.                                     updatedXml = configSection.SerializeSection(parentConfigSection, configSection.SectionInformation.Name, saveMode);
  1659.                                     ValidateSectionXml(updatedXml, configKey);
  1660.                                 }
  1661.                                 else {
  1662.                                     updatedXml = configSection.SectionInformation.RawXml;
  1663.                                 }
  1664.                                
  1665.                                 if (string.IsNullOrEmpty(updatedXml)) {
  1666.                                     //
  1667.                                     // We always need to emit a section, even if empty, when:
  1668.                                     // * The section has configSoure
  1669.                                     // * The section is in a location section that has non-default attributes
  1670.                                     // * The section is encrypted.
  1671.                                     //
  1672.                                     if (!String.IsNullOrEmpty(configSection.SectionInformation.ConfigSource) || !configSection.SectionInformation.LocationAttributesAreDefault || (configSection.SectionInformation.ProtectionProvider != null)) {
  1673.                                        
  1674.                                         updatedXml = WriteEmptyElement(configSection.SectionInformation.Name);
  1675.                                     }
  1676.                                 }
  1677.                                
  1678.                                 if (string.IsNullOrEmpty(updatedXml)) {
  1679.                                     configSection.SectionInformation.Removed = true;
  1680.                                     // configSection.ElementPresent = false;
  1681.                                     updatedXml = null;
  1682.                                     addUpdate = false;
  1683.                                     if (sectionRecord.HasFileInput) {
  1684.                                         hasChanged = true;
  1685.                                     }
  1686.                                 }
  1687.                                 else {
  1688.                                     // configSection.ElementPresent = true;
  1689.                                     if (sectionAttributesModified || moved || String.IsNullOrEmpty(configSection.SectionInformation.ConfigSource)) {
  1690.                                         hasChanged = true;
  1691.                                     }
  1692.                                    
  1693.                                     // Encrypt if required.
  1694.                                     if (configSection.SectionInformation.ProtectionProvider != null) {
  1695.                                         ProtectedConfigurationSection protectedConfig = GetSection(BaseConfigurationRecord.RESERVED_SECTION_PROTECTED_CONFIGURATION) as ProtectedConfigurationSection;
  1696.                                         try {
  1697.                                             string encryptedSection = Host.EncryptSection(updatedXml, configSection.SectionInformation.ProtectionProvider, protectedConfig);
  1698.                                            
  1699.                                             updatedXml = ProtectedConfigurationSection.FormatEncryptedSection(encryptedSection, configSection.SectionInformation.Name, configSection.SectionInformation.ProtectionProvider.Name);
  1700.                                         }
  1701.                                         catch (Exception e) {
  1702.                                             throw new ConfigurationErrorsException(SR.GetString(SR.Encryption_failed, configSection.SectionInformation.SectionName, configSection.SectionInformation.ProtectionProvider.Name, e.Message), e);
  1703.                                         }
  1704.                                         catch {
  1705.                                             throw new ConfigurationErrorsException(SR.GetString(SR.Encryption_failed, configSection.SectionInformation.SectionName, configSection.SectionInformation.ProtectionProvider.Name, ExceptionUtil.NoExceptionInformation));
  1706.                                         }
  1707.                                     }
  1708.                                 }
  1709.                             }
  1710.                             else if (configSection.SectionInformation.Removed) {
  1711.                                 addUpdate = false;
  1712.                                 if (sectionRecord.HasFileInput) {
  1713.                                     hasChanged = true;
  1714.                                 }
  1715.                             }
  1716.                         }
  1717.                         catch (Exception e) {
  1718.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_exception_in_config_section_handler, configSection.SectionInformation.SectionName), e);
  1719.                         }
  1720.                         catch {
  1721.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_exception_in_config_section_handler, configSection.SectionInformation.SectionName));
  1722.                         }
  1723.                     }
  1724.                    
  1725.                     if (addUpdate) {
  1726.                         VerifySectionUnlocked(sectionRecord.ConfigKey, null);
  1727.                         sectionRecord.AddUpdate = true;
  1728.                         DefinitionUpdate definitionUpdate = definitionUpdates.AddUpdate(allowOverride, inheritInChildApplications, moved, updatedXml, sectionRecord);
  1729.                         if (addToConfigSourceUpdates) {
  1730.                             if (configSourceUpdates == null) {
  1731.                                 configSourceUpdates = new ArrayList();
  1732.                             }
  1733.                            
  1734.                             configSourceUpdates.Add(definitionUpdate);
  1735.                         }
  1736.                     }
  1737.                 }
  1738.             }
  1739.            
  1740.             if (_flags[ForceLocationWritten]) {
  1741.                 // We must write the location tag
  1742.                 hasChanged = true;
  1743.                 definitionUpdates.RequireLocation = true;
  1744.             }
  1745.            
  1746.             if (_flags[SuggestLocationRemoval]) {
  1747.                 // We should try to remove location
  1748.                 hasChanged = true;
  1749.             }
  1750.            
  1751.             if (hasChanged) {
  1752.                 definitionUpdates.CompleteUpdates();
  1753.             }
  1754.             else {
  1755.                 definitionUpdates = null;
  1756.             }
  1757.         }
  1758.        
  1759.         //
  1760.         // WriteEmptyElement
  1761.         //
  1762.         // Take a element name, and create an xml string that contains
  1763.         // that element in an empty state
  1764.         //
  1765.         private string WriteEmptyElement(string ElementName)
  1766.         {
  1767.             StringBuilder sb;
  1768.            
  1769.             sb = new StringBuilder();
  1770.            
  1771.             // Create element
  1772.             sb.Append('<');
  1773.             sb.Append(ElementName);
  1774.             sb.Append(" />");
  1775.            
  1776.             return sb.ToString();
  1777.         }
  1778.        
  1779.         // After the config file has been written out, update the section records
  1780.         // to reflect changes that were made in the config file.
  1781.         private void UpdateRecords()
  1782.         {
  1783.             if (_factoryRecords != null) {
  1784.                 foreach (FactoryRecord factoryRecord in _factoryRecords.Values) {
  1785.                     // Update stream information
  1786.                     if (String.IsNullOrEmpty(factoryRecord.Filename)) {
  1787.                         factoryRecord.Filename = ConfigStreamInfo.StreamName;
  1788.                     }
  1789.                    
  1790.                     factoryRecord.LineNumber = 0;
  1791.                    
  1792.                     ConfigurationSection configSection = GetConfigSection(factoryRecord.ConfigKey);
  1793.                     if (configSection != null) {
  1794.                         if (configSection.SectionInformation.Type != null) {
  1795.                             factoryRecord.FactoryTypeName = configSection.SectionInformation.Type;
  1796.                         }
  1797.                        
  1798.                         factoryRecord.AllowLocation = configSection.SectionInformation.AllowLocation;
  1799.                         factoryRecord.RestartOnExternalChanges = configSection.SectionInformation.RestartOnExternalChanges;
  1800.                         factoryRecord.RequirePermission = configSection.SectionInformation.RequirePermission;
  1801.                         factoryRecord.AllowDefinition = configSection.SectionInformation.AllowDefinition;
  1802.                         factoryRecord.AllowExeDefinition = configSection.SectionInformation.AllowExeDefinition;
  1803.                     }
  1804.                 }
  1805.             }
  1806.            
  1807.             if (_sectionRecords != null) {
  1808.                 string definitionConfigPath = (IsLocationConfig) ? _parent.ConfigPath : ConfigPath;
  1809.                 foreach (SectionRecord sectionRecord in _sectionRecords.Values) {
  1810.                     string configSource;
  1811.                     string configSourceStreamName;
  1812.                     object configSourceStreamVersion;
  1813.                     ConfigurationSection configSection;
  1814.                    
  1815.                     if (sectionRecord.HasResult) {
  1816.                         configSection = (ConfigurationSection)sectionRecord.Result;
  1817.                         configSource = configSection.SectionInformation.ConfigSource;
  1818.                         if (String.IsNullOrEmpty(configSource)) {
  1819.                             configSource = null;
  1820.                         }
  1821.                        
  1822.                         configSourceStreamName = configSection.SectionInformation.ConfigSourceStreamName;
  1823.                         if (String.IsNullOrEmpty(configSourceStreamName)) {
  1824.                             configSourceStreamName = null;
  1825.                         }
  1826.                     }
  1827.                     else {
  1828.                         configSection = null;
  1829.                         configSource = null;
  1830.                         configSourceStreamName = null;
  1831.                        
  1832.                         // If there is no result, then the only way there could be a
  1833.                         // section record is:
  1834.                         // 1. For there to be input in the file.
  1835.                         // 2. A location tag applies to this record
  1836.                         Debug.Assert(sectionRecord.HasFileInput || sectionRecord.HasLocationInputs, "sectionRecord.HasFileInput || sectionRecord.HasLocationInputs");
  1837.                        
  1838.                         // Note that if it's a location input, we don't need to monitor the configSource because
  1839.                         // that stream is monitored by one of our parent's config record
  1840.                         if (sectionRecord.HasFileInput) {
  1841.                             SectionXmlInfo sectionXmlInfo = sectionRecord.FileInput.SectionXmlInfo;
  1842.                             configSource = sectionXmlInfo.ConfigSource;
  1843.                             configSourceStreamName = sectionXmlInfo.ConfigSourceStreamName;
  1844.                         }
  1845.                     }
  1846.                    
  1847.                     if (!String.IsNullOrEmpty(configSource)) {
  1848.                         configSourceStreamVersion = MonitorStream(sectionRecord.ConfigKey, configSource, configSourceStreamName);
  1849.                     }
  1850.                     else {
  1851.                         configSourceStreamVersion = null;
  1852.                     }
  1853.                    
  1854.                     if (!sectionRecord.HasResult) {
  1855.                         Debug.Assert(sectionRecord.HasFileInput || sectionRecord.HasLocationInputs, "sectionRecord.HasFileInput || sectionRecord.HasLocationInputs");
  1856.                        
  1857.                         // Note that if it's a location input, we don't need to monitor the configSource because
  1858.                         // that stream is monitored by one of our parent's config record
  1859.                         if (sectionRecord.HasFileInput) {
  1860.                             SectionXmlInfo sectionXmlInfo = sectionRecord.FileInput.SectionXmlInfo;
  1861.                             sectionXmlInfo.StreamVersion = ConfigStreamInfo.StreamVersion;
  1862.                             sectionXmlInfo.ConfigSourceStreamVersion = configSourceStreamVersion;
  1863.                         }
  1864.                     }
  1865.                     else {
  1866.                         configSection.SectionInformation.RawXml = null;
  1867.                         bool addUpdate = sectionRecord.AddUpdate;
  1868.                         sectionRecord.AddUpdate = false;
  1869.                        
  1870.                         if (addUpdate) {
  1871.                             SectionInput fileInput = sectionRecord.FileInput;
  1872.                             if (fileInput == null) {
  1873.                                 SectionXmlInfo sectionXmlInfo = new SectionXmlInfo(sectionRecord.ConfigKey, definitionConfigPath, _configPath, _locationSubPath, ConfigStreamInfo.StreamName, 0, ConfigStreamInfo.StreamVersion, null, configSource, configSourceStreamName,
  1874.                                 configSourceStreamVersion, configSection.SectionInformation.ProtectionProviderName, !configSection.SectionInformation.AllowOverride, !configSection.SectionInformation.InheritInChildApplications);
  1875.                                
  1876.                                 fileInput = new SectionInput(sectionXmlInfo, null);
  1877.                                 fileInput.Result = configSection;
  1878.                                 fileInput.ResultRuntimeObject = configSection;
  1879.                                 sectionRecord.AddFileInput(fileInput);
  1880.                             }
  1881.                             else {
  1882.                                 SectionXmlInfo sectionXmlInfo = fileInput.SectionXmlInfo;
  1883.                                 sectionXmlInfo.LineNumber = 0;
  1884.                                 sectionXmlInfo.StreamVersion = ConfigStreamInfo.StreamVersion;
  1885.                                
  1886.                                 sectionXmlInfo.RawXml = null;
  1887.                                 sectionXmlInfo.ConfigSource = configSource;
  1888.                                 sectionXmlInfo.ConfigSourceStreamName = configSourceStreamName;
  1889.                                 sectionXmlInfo.ConfigSourceStreamVersion = configSourceStreamVersion;
  1890.                                 sectionXmlInfo.ProtectionProviderName = configSection.SectionInformation.ProtectionProviderName;
  1891.                                 sectionXmlInfo.LockChildren = !configSection.SectionInformation.AllowOverride;
  1892.                                 sectionXmlInfo.SkipInChildApps = !configSection.SectionInformation.InheritInChildApplications;
  1893.                             }
  1894.                            
  1895.                             fileInput.ProtectionProvider = configSection.SectionInformation.ProtectionProvider;
  1896.                         }
  1897.                        
  1898.                         try {
  1899.                             configSection.ResetModified();
  1900.                         }
  1901.                         catch (Exception e) {
  1902.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_exception_in_config_section_handler, sectionRecord.ConfigKey), e, ConfigStreamInfo.StreamName, 0);
  1903.                         }
  1904.                         catch {
  1905.                             throw new ConfigurationErrorsException(SR.GetString(SR.Config_exception_in_config_section_handler, sectionRecord.ConfigKey), null, ConfigStreamInfo.StreamName, 0);
  1906.                         }
  1907.                     }
  1908.                 }
  1909.             }
  1910.            
  1911.             // Copy remaining stream updates, which correspond to streams used by location sections
  1912.             foreach (StreamInfo streamInfo in _streamInfoUpdates.Values) {
  1913.                 if (!ConfigStreamInfo.StreamInfos.Contains(streamInfo.StreamName)) {
  1914.                     MonitorStream(streamInfo.SectionName, streamInfo.ConfigSource, streamInfo.StreamName);
  1915.                 }
  1916.             }
  1917.            
  1918.             // reinitialize _streamInfoUpdates
  1919.             InitStreamInfoUpdates();
  1920.            
  1921.             // Update namespace value
  1922.             _flags[NamespacePresentInFile] = _flags[NamespacePresentCurrent];
  1923.            
  1924.             // You only have one chance to force the location config, now you
  1925.             // will have to recreate the object
  1926.             _flags[ForceLocationWritten] = false;
  1927.             _flags[SuggestLocationRemoval] = false;
  1928.            
  1929.             // Handle removed location sections
  1930.             if (!IsLocationConfig && _locationSections != null && _removedSections != null && _removedSections.Count > 0) {
  1931.                 int i = 0;
  1932.                 while (i < _locationSections.Count) {
  1933.                     LocationSectionRecord locationSectionRecord = (LocationSectionRecord)_locationSections[i];
  1934.                     if (_removedSections.Contains(locationSectionRecord.ConfigKey)) {
  1935.                         _locationSections.RemoveAt(i);
  1936.                     }
  1937.                     else {
  1938.                         i++;
  1939.                     }
  1940.                 }
  1941.             }
  1942.            
  1943.             _removedSections = null;
  1944.             _removedSectionGroups = null;
  1945.         }
  1946.        
  1947.         // Create a new config file.
  1948.         private void CreateNewConfig(SectionUpdates declarationUpdates, ConfigDefinitionUpdates definitionUpdates, NamespaceChange namespaceChange, XmlUtilWriter utilWriter)
  1949.         {
  1950.             int linePosition = DEFAULT_INDENT + 1;
  1951.             int indent = DEFAULT_INDENT;
  1952.            
  1953.             // Write Header
  1954.             utilWriter.Write(string.Format(CultureInfo.InvariantCulture, FORMAT_NEWCONFIGFILE, ConfigStreamInfo.StreamEncoding.WebName));
  1955.            
  1956.             // Write <configuration> tag
  1957.             if (namespaceChange == NamespaceChange.Add) {
  1958.                 utilWriter.Write(string.Format(CultureInfo.InvariantCulture, FORMAT_CONFIGURATION_NAMESPACE, KEYWORD_CONFIGURATION_NAMESPACE));
  1959.             }
  1960.             else {
  1961.                 utilWriter.Write(FORMAT_CONFIGURATION);
  1962.             }
  1963.            
  1964.            
  1965.             if (declarationUpdates != null) {
  1966.                 WriteNewConfigDeclarations(declarationUpdates, utilWriter, linePosition, indent, false);
  1967.             }
  1968.            
  1969.             WriteNewConfigDefinitions(definitionUpdates, utilWriter, linePosition, indent);
  1970.            
  1971.             utilWriter.Write(FORMAT_CONFIGURATION_ENDELEMENT);
  1972.         }
  1973.        
  1974.         private void WriteNewConfigDeclarations(SectionUpdates declarationUpdates, XmlUtilWriter utilWriter, int linePosition, int indent, bool skipFirstIndent)
  1975.         {
  1976.             if (!skipFirstIndent) {
  1977.                 utilWriter.AppendSpacesToLinePosition(linePosition);
  1978.             }
  1979.            
  1980.             utilWriter.Write("<configSections>\r\n");
  1981.             WriteUnwrittenConfigDeclarations(declarationUpdates, utilWriter, linePosition + indent, indent, false);
  1982.             utilWriter.AppendSpacesToLinePosition(linePosition);
  1983.             utilWriter.Write("</configSections>\r\n");
  1984.            
  1985.             if (skipFirstIndent) {
  1986.                 utilWriter.AppendSpacesToLinePosition(linePosition);
  1987.             }
  1988.         }
  1989.        
  1990.         private void WriteUnwrittenConfigDeclarations(SectionUpdates declarationUpdates, XmlUtilWriter utilWriter, int linePosition, int indent, bool skipFirstIndent)
  1991.         {
  1992.             WriteUnwrittenConfigDeclarationsRecursive(declarationUpdates, utilWriter, linePosition, indent, skipFirstIndent);
  1993.         }
  1994.        
  1995.         private void WriteUnwrittenConfigDeclarationsRecursive(SectionUpdates declarationUpdates, XmlUtilWriter utilWriter, int linePosition, int indent, bool skipFirstIndent)
  1996.         {
  1997.             string[] unretrievedSectionNames = declarationUpdates.GetUnretrievedSectionNames();
  1998.             if (unretrievedSectionNames != null) {
  1999.                 foreach (string configKey in unretrievedSectionNames) {
  2000.                     Debug.Assert(!IsImplicitSection(configKey), "We should never write out an implicit section");
  2001.                     if (!skipFirstIndent) {
  2002.                         utilWriter.AppendSpacesToLinePosition(linePosition);
  2003.                     }
  2004.                     skipFirstIndent = false;
  2005.                    
  2006.                     DeclarationUpdate update = declarationUpdates.GetDeclarationUpdate(configKey);
  2007.                     utilWriter.Write(update.UpdatedXml);
  2008.                     utilWriter.AppendNewLine();
  2009.                 }
  2010.             }
  2011.            
  2012.             string[] unretrievedGroupNames = declarationUpdates.GetUnretrievedGroupNames();
  2013.             if (unretrievedGroupNames != null) {
  2014.                 foreach (string group in unretrievedGroupNames) {
  2015.                     if (!skipFirstIndent) {
  2016.                         utilWriter.AppendSpacesToLinePosition(linePosition);
  2017.                     }
  2018.                     skipFirstIndent = false;
  2019.                    
  2020.                     SectionUpdates declarationUpdatesChild = declarationUpdates.GetSectionUpdatesForGroup(group);
  2021.                     DeclarationUpdate groupUpdate = declarationUpdatesChild.GetSectionGroupUpdate();
  2022.                     if (groupUpdate == null) {
  2023.                         utilWriter.Write("<sectionGroup name=\"" + group + "\">");
  2024.                     }
  2025.                     else {
  2026.                         utilWriter.Write(groupUpdate.UpdatedXml);
  2027.                     }
  2028.                     utilWriter.AppendNewLine();
  2029.                    
  2030.                     WriteUnwrittenConfigDeclarationsRecursive(declarationUpdatesChild, utilWriter, linePosition + indent, indent, false);
  2031.                     utilWriter.AppendSpacesToLinePosition(linePosition);
  2032.                     utilWriter.Write("</sectionGroup>\r\n");
  2033.                 }
  2034.             }
  2035.         }
  2036.        
  2037.         private void WriteNewConfigDefinitions(ConfigDefinitionUpdates configDefinitionUpdates, XmlUtilWriter utilWriter, int linePosition, int indent)
  2038.         {
  2039.             if (configDefinitionUpdates == null)
  2040.                 return;
  2041.            
  2042.             foreach (LocationUpdates locationUpdates in configDefinitionUpdates.LocationUpdatesList) {
  2043.                 SectionUpdates sectionUpdates = locationUpdates.SectionUpdates;
  2044.                 if (sectionUpdates.IsEmpty || !sectionUpdates.IsNew)
  2045.                     continue;
  2046.                
  2047.                 configDefinitionUpdates.FlagLocationWritten();
  2048.                 bool writeLocationTag = _locationSubPath != null || !locationUpdates.IsDefault;
  2049.                 int recurseLinePosition = linePosition;
  2050.                
  2051.                 utilWriter.AppendSpacesToLinePosition(linePosition);
  2052.                
  2053.                 if (writeLocationTag) {
  2054.                     // write the <location> start tag
  2055.                     if (_locationSubPath == null) {
  2056.                         utilWriter.Write(String.Format(CultureInfo.InvariantCulture, FORMAT_LOCATION_NOPATH, BoolToString(locationUpdates.AllowOverride), BoolToString(locationUpdates.InheritInChildApps)));
  2057.                     }
  2058.                     else {
  2059.                         utilWriter.Write(String.Format(CultureInfo.InvariantCulture, FORMAT_LOCATION_PATH, BoolToString(locationUpdates.AllowOverride), BoolToString(locationUpdates.InheritInChildApps), _locationSubPath));
  2060.                     }
  2061.                    
  2062.                     recurseLinePosition += indent;
  2063.                     utilWriter.AppendSpacesToLinePosition(recurseLinePosition);
  2064.                 }
  2065.                
  2066.                 // Invoke the recursive write.
  2067.                 WriteNewConfigDefinitionsRecursive(utilWriter, locationUpdates.SectionUpdates, recurseLinePosition, indent, true);
  2068.                
  2069.                 if (writeLocationTag) {
  2070.                     // Write the location end tag
  2071.                     utilWriter.AppendSpacesToLinePosition(linePosition);
  2072.                     utilWriter.Write(FORMAT_LOCATION_ENDELEMENT);
  2073.                     utilWriter.AppendNewLine();
  2074.                 }
  2075.             }
  2076.            
  2077.             if (configDefinitionUpdates.RequireLocation) {
  2078.                 Debug.Assert(IsLocationConfig, "IsLocationConfig");
  2079.                
  2080.                 // If we still require this to be written, then we must write it out now
  2081.                 configDefinitionUpdates.FlagLocationWritten();
  2082.                
  2083.                 utilWriter.AppendSpacesToLinePosition(linePosition);
  2084.                
  2085.                 utilWriter.Write(String.Format(CultureInfo.InvariantCulture, FORMAT_LOCATION_PATH, KEYWORD_TRUE, KEYWORD_TRUE, _locationSubPath));
  2086.                 utilWriter.AppendSpacesToLinePosition(linePosition);
  2087.                 utilWriter.Write(FORMAT_LOCATION_ENDELEMENT);
  2088.                 utilWriter.AppendNewLine();
  2089.             }
  2090.         }
  2091.        
  2092.         // Recursively write new sections for each section group.
  2093.         private bool WriteNewConfigDefinitionsRecursive(XmlUtilWriter utilWriter, SectionUpdates sectionUpdates, int linePosition, int indent, bool skipFirstIndent)
  2094.         {
  2095.             bool wroteASection = false;
  2096.            
  2097.             string[] movedSectionNames = sectionUpdates.GetMovedSectionNames();
  2098.             if (movedSectionNames != null) {
  2099.                 wroteASection = true;
  2100.                 foreach (string configKey in movedSectionNames) {
  2101.                     DefinitionUpdate update = sectionUpdates.GetDefinitionUpdate(configKey);
  2102.                     WriteSectionUpdate(utilWriter, update, linePosition, indent, skipFirstIndent);
  2103.                     utilWriter.AppendNewLine();
  2104.                     skipFirstIndent = false;
  2105.                 }
  2106.             }
  2107.            
  2108.             string[] newGroupNames = sectionUpdates.GetNewGroupNames();
  2109.             if (newGroupNames != null) {
  2110.                 foreach (string group in newGroupNames) {
  2111.                     if (!skipFirstIndent) {
  2112.                         utilWriter.AppendSpacesToLinePosition(linePosition);
  2113.                     }
  2114.                     skipFirstIndent = false;
  2115.                    
  2116.                     utilWriter.Write("<" + group + ">\r\n");
  2117.                     bool recurseWroteASection = WriteNewConfigDefinitionsRecursive(utilWriter, sectionUpdates.GetSectionUpdatesForGroup(group), linePosition + indent, indent, false);
  2118.                    
  2119.                     if (recurseWroteASection) {
  2120.                         wroteASection = true;
  2121.                     }
  2122.                    
  2123.                     utilWriter.AppendSpacesToLinePosition(linePosition);
  2124.                     utilWriter.Write("</" + group + ">\r\n");
  2125.                 }
  2126.             }
  2127.            
  2128.             sectionUpdates.IsNew = false;
  2129.            
  2130.             return wroteASection;
  2131.         }
  2132.        
  2133.         private void CheckPreamble(byte[] preamble, XmlUtilWriter utilWriter, byte[] buffer)
  2134.         {
  2135.             bool hasByteOrderMark = false;
  2136.             using (Stream preambleStream = new MemoryStream(buffer)) {
  2137.                 byte[] streamStart = new byte[preamble.Length];
  2138.                 if (preambleStream.Read(streamStart, 0, streamStart.Length) == streamStart.Length) {
  2139.                     hasByteOrderMark = true;
  2140.                     for (int i = 0; i < streamStart.Length; i++) {
  2141.                         if (streamStart[i] != preamble[i]) {
  2142.                             hasByteOrderMark = false;
  2143.                             break;
  2144.                         }
  2145.                     }
  2146.                 }
  2147.             }
  2148.            
  2149.             if (!hasByteOrderMark) {
  2150.                 // Force the writer to emit byte order mark, then reset the stream
  2151.                 // so that it is written over.
  2152.                 object checkpoint = utilWriter.CreateStreamCheckpoint();
  2153.                 utilWriter.Write('x');
  2154.                 utilWriter.RestoreStreamCheckpoint(checkpoint);
  2155.             }
  2156.         }
  2157.        
  2158.         //
  2159.         // Calculate a new indent based on the position of the parent element and the current node.
  2160.         //
  2161.         private int UpdateIndent(int oldIndent, XmlUtil xmlUtil, XmlUtilWriter utilWriter, int parentLinePosition)
  2162.         {
  2163.             int indent = oldIndent;
  2164.             if (xmlUtil.Reader.NodeType == XmlNodeType.Element && utilWriter.IsLastLineBlank) {
  2165.                 int childLinePosition = xmlUtil.TrueLinePosition;
  2166.                 if (parentLinePosition < childLinePosition && childLinePosition <= parentLinePosition + MAX_INDENT) {
  2167.                     indent = childLinePosition - parentLinePosition;
  2168.                 }
  2169.             }
  2170.            
  2171.             return indent;
  2172.         }
  2173.        
  2174.         // Copy a config file, replacing sections with updates.
  2175.         private void CopyConfig(SectionUpdates declarationUpdates, ConfigDefinitionUpdates definitionUpdates, byte[] buffer, string filename, NamespaceChange namespaceChange, XmlUtilWriter utilWriter)
  2176.         {
  2177.            
  2178.             CheckPreamble(ConfigStreamInfo.StreamEncoding.GetPreamble(), utilWriter, buffer);
  2179.            
  2180.             using (Stream stream = new MemoryStream(buffer)) {
  2181.                 using (XmlUtil xmlUtil = new XmlUtil(stream, filename, false)) {
  2182.                     // copy up to the <configuration> node
  2183.                     XmlTextReader reader = xmlUtil.Reader;
  2184.                     reader.WhitespaceHandling = WhitespaceHandling.All;
  2185.                     reader.Read();
  2186.                     xmlUtil.CopyReaderToNextElement(utilWriter, false);
  2187.                    
  2188.                     Debug.Assert(reader.NodeType == XmlNodeType.Element && reader.Name == KEYWORD_CONFIGURATION, "reader.NodeType == XmlNodeType.Element && reader.Name == KEYWORD_CONFIGURATION");
  2189.                    
  2190.                     int indent = DEFAULT_INDENT;
  2191.                     int configurationElementLinePosition = xmlUtil.TrueLinePosition;
  2192.                     bool isEmptyConfigurationElement = reader.IsEmptyElement;
  2193.                    
  2194.                     // copy <configuration> node
  2195.                     // if the node is an empty element, we may need to open it.
  2196.                     string configurationStartElement;
  2197.                     if (namespaceChange == NamespaceChange.Add) {
  2198.                         configurationStartElement = string.Format(CultureInfo.InvariantCulture, FORMAT_CONFIGURATION_NAMESPACE, KEYWORD_CONFIGURATION_NAMESPACE);
  2199.                     }
  2200.                     else if (namespaceChange == NamespaceChange.Remove) {
  2201.                         configurationStartElement = FORMAT_CONFIGURATION;
  2202.                     }
  2203.                     else {
  2204.                         configurationStartElement = null;
  2205.                     }
  2206.                    
  2207.                     bool needsChildren = (declarationUpdates != null || definitionUpdates != null);
  2208.                     string configurationEndElement = xmlUtil.UpdateStartElement(utilWriter, configurationStartElement, needsChildren, configurationElementLinePosition, indent);
  2209.                    
  2210.                     bool foundConfigSectionsElement = false;
  2211.                     if (!isEmptyConfigurationElement) {
  2212.                         // copy up to the first element under <configuration>
  2213.                         xmlUtil.CopyReaderToNextElement(utilWriter, true);
  2214.                        
  2215.                         // updateIndent
  2216.                         indent = UpdateIndent(indent, xmlUtil, utilWriter, configurationElementLinePosition);
  2217.                        
  2218.                         if (reader.NodeType == XmlNodeType.Element && reader.Name == KEYWORD_CONFIGSECTIONS) {
  2219.                             foundConfigSectionsElement = true;
  2220.                            
  2221.                             int configSectionsElementLinePosition = xmlUtil.TrueLinePosition;
  2222.                             bool isEmptyConfigSectionsElement = reader.IsEmptyElement;
  2223.                            
  2224.                             // if no updates, copy the entire <configSections> element
  2225.                             if (declarationUpdates == null) {
  2226.                                 xmlUtil.CopyOuterXmlToNextElement(utilWriter, true);
  2227.                             }
  2228.                             else {
  2229.                                 // copy <configSections>, and open it if it is an empty element
  2230.                                 string configSectionsEndElement = xmlUtil.UpdateStartElement(utilWriter, null, true, configSectionsElementLinePosition, indent);
  2231.                                
  2232.                                 if (!isEmptyConfigSectionsElement) {
  2233.                                     // copy to next element under <configSections>, or up to closing </configSections>
  2234.                                     xmlUtil.CopyReaderToNextElement(utilWriter, true);
  2235.                                    
  2236.                                     // copy config declarations
  2237.                                     CopyConfigDeclarationsRecursive(declarationUpdates, xmlUtil, utilWriter, string.Empty, configSectionsElementLinePosition, indent);
  2238.                                    
  2239.                                     Debug.Assert(reader.NodeType == XmlNodeType.EndElement && reader.Name == KEYWORD_CONFIGSECTIONS, "reader.NodeType == XmlNodeType.EndElement && reader.Name == \"KEYWORD_CONFIGSECTIONS\"");
  2240.                                 }
  2241.                                
  2242.                                 // write declarations not written by above copy
  2243.                                 if (declarationUpdates.HasUnretrievedSections()) {
  2244.                                    
  2245.                                     // determine the line position of the end element
  2246.                                     int endElementLinePosition = 0;
  2247.                                     if (configSectionsEndElement == null) {
  2248.                                         endElementLinePosition = xmlUtil.TrueLinePosition;
  2249.                                     }
  2250.                                    
  2251.                                     // indent a new line
  2252.                                     if (!utilWriter.IsLastLineBlank) {
  2253.                                         utilWriter.AppendNewLine();
  2254.                                     }
  2255.                                    
  2256.                                     WriteUnwrittenConfigDeclarations(declarationUpdates, utilWriter, configSectionsElementLinePosition + indent, indent, false);
  2257.                                    
  2258.                                     // restore spaces to end element
  2259.                                     if (configSectionsEndElement == null) {
  2260.                                         utilWriter.AppendSpacesToLinePosition(endElementLinePosition);
  2261.                                     }
  2262.                                 }
  2263.                                
  2264.                                 // Copy the </configSections> element
  2265.                                 if (configSectionsEndElement == null) {
  2266.                                     xmlUtil.CopyXmlNode(utilWriter);
  2267.                                 }
  2268.                                 else {
  2269.                                     // note that configSectionsEndElement already contains the proper indenting
  2270.                                     utilWriter.Write(configSectionsEndElement);
  2271.                                 }
  2272.                                
  2273.                                 // copy up to the next element under <configuration>, or up to closing </configSections>
  2274.                                 xmlUtil.CopyReaderToNextElement(utilWriter, true);
  2275.                             }
  2276.                         }
  2277.                     }
  2278.                    
  2279.                     // Write new declarations
  2280.                     if (!foundConfigSectionsElement && declarationUpdates != null) {
  2281.                         bool skipFirstIndent = reader.Depth > 0 && reader.NodeType == XmlNodeType.Element;
  2282.                         int newConfigSectionsLinePosition;
  2283.                         if (skipFirstIndent) {
  2284.                             newConfigSectionsLinePosition = xmlUtil.TrueLinePosition;
  2285.                         }
  2286.                         else {
  2287.                             newConfigSectionsLinePosition = configurationElementLinePosition + indent;
  2288.                         }
  2289.                        
  2290.                         WriteNewConfigDeclarations(declarationUpdates, utilWriter, newConfigSectionsLinePosition, indent, skipFirstIndent);
  2291.                     }
  2292.                    
  2293.                     if (definitionUpdates != null) {
  2294.                         //
  2295.                         // Copy sections recursively. In the file we copy we start out at
  2296.                         // location path="." allowOverride="true" inheritInChildApps="true"
  2297.                         //
  2298.                         bool locationPathApplies = false;
  2299.                         LocationUpdates locationUpdates = null;
  2300.                         SectionUpdates sectionUpdates = null;
  2301.                         if (!IsLocationConfig) {
  2302.                             locationPathApplies = true;
  2303.                             locationUpdates = definitionUpdates.FindLocationUpdates(true, true);
  2304.                             if (locationUpdates != null) {
  2305.                                 sectionUpdates = locationUpdates.SectionUpdates;
  2306.                             }
  2307.                         }
  2308.                        
  2309.                         CopyConfigDefinitionsRecursive(definitionUpdates, xmlUtil, utilWriter, locationPathApplies, locationUpdates, sectionUpdates, true, string.Empty, configurationElementLinePosition, indent
  2310.                         );
  2311.                        
  2312.                         // Write new config sections from new groups.
  2313.                         WriteNewConfigDefinitions(definitionUpdates, utilWriter, configurationElementLinePosition + indent, indent);
  2314.                        
  2315.                         #if DBG
  2316.                         Debug.Assert(configurationEndElement != null || (reader.NodeType == XmlNodeType.EndElement && reader.Name == KEYWORD_CONFIGURATION), "configurationEndElement != null || (reader.NodeType == XmlNodeType.EndElement && reader.Name == KEYWORD_CONFIGURATION)");
  2317.                         #endif
  2318.                        
  2319.                        
  2320.                        
  2321.                         #if DBG
  2322.                         {
  2323.                             foreach (LocationUpdates l in definitionUpdates.LocationUpdatesList) {
  2324.                                 Debug.Assert(!l.SectionUpdates.HasUnretrievedSections(), "!l.SectionUpdates.HasUnretrievedSections()");
  2325.                             }
  2326.                         }
  2327.                         #endif
  2328.                     }
  2329.                    
  2330.                    
  2331.                     if (configurationEndElement != null) {
  2332.                         // If we have to add closing config tag, then do it now
  2333.                         // before copying extra whitespace/comments
  2334.                         if (!utilWriter.IsLastLineBlank) {
  2335.                             utilWriter.AppendNewLine();
  2336.                         }
  2337.                        
  2338.                         utilWriter.Write(configurationEndElement);
  2339.                     }
  2340.                    
  2341.                     //
  2342.                     // Copy the remainder of the file, the closing </configuration> node plus any whitespace
  2343.                     // and comments
  2344.                     //
  2345.                     while (xmlUtil.CopyXmlNode(utilWriter)) {
  2346.                     }
  2347.                 }
  2348.             }
  2349.         }
  2350.        
  2351.         private bool CopyConfigDeclarationsRecursive(SectionUpdates declarationUpdates, XmlUtil xmlUtil, XmlUtilWriter utilWriter, string group, int parentLinePosition, int parentIndent)
  2352.         {
  2353.            
  2354.             bool wroteASection = false;
  2355.             XmlTextReader reader = xmlUtil.Reader;
  2356.             int linePosition;
  2357.             int indent;
  2358.             int startingLinePosition;
  2359.            
  2360.             indent = UpdateIndent(parentIndent, xmlUtil, utilWriter, parentLinePosition);
  2361.            
  2362.             if (reader.NodeType == XmlNodeType.Element) {
  2363.                 linePosition = xmlUtil.TrueLinePosition;
  2364.                 startingLinePosition = linePosition;
  2365.             }
  2366.             else if (reader.NodeType == XmlNodeType.EndElement) {
  2367.                 linePosition = parentLinePosition + indent;
  2368.                 if (utilWriter.IsLastLineBlank) {
  2369.                     startingLinePosition = xmlUtil.TrueLinePosition;
  2370.                 }
  2371.                 else {
  2372.                     startingLinePosition = parentLinePosition;
  2373.                 }
  2374.             }
  2375.             else {
  2376.                 linePosition = parentLinePosition + indent;
  2377.                 startingLinePosition = 0;
  2378.             }
  2379.            
  2380.             //
  2381.             // Write any new section declarations that apply to this group
  2382.             //
  2383.             if (declarationUpdates != null) {
  2384.                 string[] movedSectionNames = declarationUpdates.GetMovedSectionNames();
  2385.                 if (movedSectionNames != null) {
  2386.                     if (!utilWriter.IsLastLineBlank) {
  2387.                         utilWriter.AppendNewLine();
  2388.                     }
  2389.                    
  2390.                     foreach (string configKey in movedSectionNames) {
  2391.                         DeclarationUpdate sectionUpdate = declarationUpdates.GetDeclarationUpdate(configKey);
  2392.                         Debug.Assert(!IsImplicitSection(configKey), "We should never write out an implicit section");
  2393.                        
  2394.                         // Write the one line section declaration.
  2395.                         utilWriter.AppendSpacesToLinePosition(linePosition);
  2396.                         utilWriter.Write(sectionUpdate.UpdatedXml);
  2397.                         utilWriter.AppendNewLine();
  2398.                        
  2399.                         wroteASection = true;
  2400.                     }
  2401.                    
  2402.                     // Restore the whitespace we used for the first element, which is either a start or an end element.
  2403.                     utilWriter.AppendSpacesToLinePosition(startingLinePosition);
  2404.                 }
  2405.             }
  2406.            
  2407.             if (reader.NodeType == XmlNodeType.Element) {
  2408.                 //
  2409.                 // For each element at this depth, either:
  2410.                 // - Write the element verbatim and recurse due to a group hierarchy element.
  2411.                 // - Write the element verbatim because it is unchanged
  2412.                 // - Write the updated XML for the section.
  2413.                 // - Skip it because the section has been removed.
  2414.                 //
  2415.                 int depth = reader.Depth;
  2416.                 while (reader.Depth == depth) {
  2417.                     bool recurse = false;
  2418.                     DeclarationUpdate sectionUpdate = null;
  2419.                     DeclarationUpdate groupUpdate = null;
  2420.                     SectionUpdates declarationUpdatesChild = null;
  2421.                     SectionUpdates recurseDeclarationUpdates = declarationUpdates;
  2422.                     string recurseGroup = group;
  2423.                    
  2424.                     // update the lineposition and indent for each element
  2425.                     indent = UpdateIndent(indent, xmlUtil, utilWriter, parentLinePosition);
  2426.                     linePosition = xmlUtil.TrueLinePosition;
  2427.                    
  2428.                     string directive = reader.Name;
  2429.                     string name = reader.GetAttribute(KEYWORD_SECTIONGROUP_NAME);
  2430.                     string configKey = CombineConfigKey(group, name);
  2431.                     if (directive == KEYWORD_SECTIONGROUP) {
  2432.                         // it's a group - get the updates for children
  2433.                         declarationUpdatesChild = declarationUpdates.GetSectionUpdatesForGroup(name);
  2434.                         if (declarationUpdatesChild != null) {
  2435.                             // get the group update
  2436.                             groupUpdate = declarationUpdatesChild.GetSectionGroupUpdate();
  2437.                            
  2438.                             // recurse if there are more sections to copy
  2439.                             if (declarationUpdatesChild.HasUnretrievedSections()) {
  2440.                                 recurse = true;
  2441.                                 recurseGroup = configKey;
  2442.                                 recurseDeclarationUpdates = declarationUpdatesChild;
  2443.                             }
  2444.                         }
  2445.                     }
  2446.                     else {
  2447.                         // it is a section - get the update
  2448.                         Debug.Assert(!IsImplicitSection(configKey), "We should never write out an implicit section");
  2449.                         sectionUpdate = declarationUpdates.GetDeclarationUpdate(configKey);
  2450.                     }
  2451.                    
  2452.                     bool writeGroupUpdate = (groupUpdate != null && groupUpdate.UpdatedXml != null);
  2453.                     if (recurse) {
  2454.                         #if DBG
  2455.                         string startElementName = reader.Name;
  2456.                         #endif
  2457.                        
  2458.                         // create a checkpoint that we can revert to if no children are written
  2459.                         object checkpoint = utilWriter.CreateStreamCheckpoint();
  2460.                         string closingElement = null;
  2461.                        
  2462.                         // Copy this element node and up to the first subelement
  2463.                         if (writeGroupUpdate) {
  2464.                             // replace the element with the updated xml
  2465.                             utilWriter.Write(groupUpdate.UpdatedXml);
  2466.                            
  2467.                             // skip over the start element
  2468.                             reader.Read();
  2469.                         }
  2470.                         else {
  2471.                             closingElement = xmlUtil.UpdateStartElement(utilWriter, null, true, linePosition, indent);
  2472.                         }
  2473.                        
  2474.                         if (closingElement == null) {
  2475.                             // Only if there is a closing element should
  2476.                             // we move to it
  2477.                             xmlUtil.CopyReaderToNextElement(utilWriter, true);
  2478.                         }
  2479.                        
  2480.                         // Recurse
  2481.                         bool recurseWroteASection = CopyConfigDeclarationsRecursive(recurseDeclarationUpdates, xmlUtil, utilWriter, recurseGroup, linePosition, indent);
  2482.                        
  2483.                         if (closingElement != null) {
  2484.                             utilWriter.AppendSpacesToLinePosition(linePosition);
  2485.                             utilWriter.Write(closingElement);
  2486.                            
  2487.                             // Since we already got to </configSections> in reader, lets
  2488.                             // indent so we can copy the element in the right place
  2489.                             utilWriter.AppendSpacesToLinePosition(parentLinePosition);
  2490.                         }
  2491.                         else {
  2492.                             // Copy the end element
  2493.                             xmlUtil.CopyXmlNode(utilWriter);
  2494.                         }
  2495.                        
  2496.                         if (recurseWroteASection || writeGroupUpdate) {
  2497.                             wroteASection = true;
  2498.                         }
  2499.                         else {
  2500.                             // back out the change
  2501.                             utilWriter.RestoreStreamCheckpoint(checkpoint);
  2502.                         }
  2503.                        
  2504.                         // Copy up to the next element, or exit this level.
  2505.                         xmlUtil.CopyReaderToNextElement(utilWriter, true);
  2506.                     }
  2507.                     else {
  2508.                         bool skip;
  2509.                         bool skipChildElements = false;
  2510.                         if (sectionUpdate == null) {
  2511.                             skip = true;
  2512.                             if (writeGroupUpdate) {
  2513.                                 // Insert an empty <sectionGroup type="typename" > node, to introduce the type
  2514.                                 wroteASection = true;
  2515.                                 utilWriter.Write(groupUpdate.UpdatedXml);
  2516.                                 utilWriter.AppendNewLine();
  2517.                                 utilWriter.AppendSpacesToLinePosition(linePosition);
  2518.                                 utilWriter.Write(FORMAT_SECTIONGROUP_ENDELEMENT);
  2519.                                 utilWriter.AppendNewLine();
  2520.                                 utilWriter.AppendSpacesToLinePosition(linePosition);
  2521.                             }
  2522.                             else if (groupUpdate != null) {
  2523.                                 Debug.Assert(groupUpdate.UpdatedXml == null, "groupUpdate.UpdatedXml == null");
  2524.                                 Debug.Assert(!declarationUpdatesChild.HasUnretrievedSections(), "If the group has any unretrieved section, we should have chosen the recursive code path above.");
  2525.                                
  2526.                                 wroteASection = true;
  2527.                                 skip = false;
  2528.                                
  2529.                                 // We should skip all the child sections. If we indeed need to keep any child
  2530.                                 // section, we should have chosen the recursive code path above.
  2531.                                 skipChildElements = true;
  2532.                             }
  2533.                         }
  2534.                         else {
  2535.                             wroteASection = true;
  2536.                             if (sectionUpdate.UpdatedXml == null) {
  2537.                                 skip = false;
  2538.                             }
  2539.                             else {
  2540.                                 skip = true;
  2541.                                
  2542.                                 // Write the updated XML on a single line
  2543.                                 utilWriter.Write(sectionUpdate.UpdatedXml);
  2544.                             }
  2545.                         }
  2546.                        
  2547.                         if (skip) {
  2548.                             //
  2549.                             // Skip over the existing element, then
  2550.                             // copy up to the next element, or exit this level.
  2551.                             //
  2552.                             xmlUtil.SkipAndCopyReaderToNextElement(utilWriter, true);
  2553.                         }
  2554.                         else {
  2555.                             if (skipChildElements) {
  2556.                                 xmlUtil.SkipChildElementsAndCopyOuterXmlToNextElement(utilWriter);
  2557.                             }
  2558.                             else {
  2559.                                 // Copy this entire contents of this element and then to the next element, or exit this level.
  2560.                                 xmlUtil.CopyOuterXmlToNextElement(utilWriter, true);
  2561.                             }
  2562.                         }
  2563.                     }
  2564.                 }
  2565.             }
  2566.            
  2567.             return wroteASection;
  2568.         }
  2569.        
  2570.         // Copy configuration sections from the original configuration file.
  2571.         private bool CopyConfigDefinitionsRecursive(ConfigDefinitionUpdates configDefinitionUpdates, XmlUtil xmlUtil, XmlUtilWriter utilWriter, bool locationPathApplies, LocationUpdates locationUpdates, SectionUpdates sectionUpdates, bool addNewSections, string group, int parentLinePosition, int parentIndent
  2572.         )
  2573.         {
  2574.            
  2575.             bool wroteASection = false;
  2576.             XmlTextReader reader = xmlUtil.Reader;
  2577.             int linePosition;
  2578.             int indent;
  2579.             int startingLinePosition;
  2580.            
  2581.             indent = UpdateIndent(parentIndent, xmlUtil, utilWriter, parentLinePosition);
  2582.            
  2583.             if (reader.NodeType == XmlNodeType.Element) {
  2584.                 linePosition = xmlUtil.TrueLinePosition;
  2585.                 startingLinePosition = linePosition;
  2586.             }
  2587.             else if (reader.NodeType == XmlNodeType.EndElement) {
  2588.                 linePosition = parentLinePosition + indent;
  2589.                 if (utilWriter.IsLastLineBlank) {
  2590.                     startingLinePosition = xmlUtil.TrueLinePosition;
  2591.                 }
  2592.                 else {
  2593.                     startingLinePosition = parentLinePosition;
  2594.                 }
  2595.             }
  2596.             else {
  2597.                 linePosition = parentLinePosition + indent;
  2598.                 startingLinePosition = 0;
  2599.             }
  2600.            
  2601.             //
  2602.             // Write any new sections that apply to this group
  2603.             //
  2604.             if (sectionUpdates != null && addNewSections) {
  2605.                 // Remove newness, so we won't write again
  2606.                 sectionUpdates.IsNew = false;
  2607.                
  2608.                 Debug.Assert(locationPathApplies, "locationPathApplies");
  2609.                 string[] movedSectionNames = sectionUpdates.GetMovedSectionNames();
  2610.                 if (movedSectionNames != null) {
  2611.                     if (!utilWriter.IsLastLineBlank) {
  2612.                         utilWriter.AppendNewLine();
  2613.                     }
  2614.                    
  2615.                     utilWriter.AppendSpacesToLinePosition(linePosition);
  2616.                     bool skipFirstIndent = true;
  2617.                    
  2618.                     foreach (string configKey in movedSectionNames) {
  2619.                         DefinitionUpdate update = sectionUpdates.GetDefinitionUpdate(configKey);
  2620.                        
  2621.                         WriteSectionUpdate(utilWriter, update, linePosition, indent, skipFirstIndent);
  2622.                         skipFirstIndent = false;
  2623.                         utilWriter.AppendNewLine();
  2624.                         wroteASection = true;
  2625.                     }
  2626.                    
  2627.                     // Restore the whitespace we used for the first element, which is either a start or an end element.
  2628.                     utilWriter.AppendSpacesToLinePosition(startingLinePosition);
  2629.                 }
  2630.             }
  2631.            
  2632.             if (reader.NodeType == XmlNodeType.Element) {
  2633.                 //
  2634.                 // For each element at this depth, either:
  2635.                 // - Write the element verbatim and recurse due to a location section or group hierarchy element.
  2636.                 // - Write the element verbatim because it is unchanged, or because the current location does
  2637.                 // not apply.
  2638.                 // - Write the updated XML for the section.
  2639.                 // - Skip it because the section has been removed.
  2640.                 //
  2641.                 int depth = reader.Depth;
  2642.                 while (reader.Depth == depth) {
  2643.                     bool recurse = false;
  2644.                     DefinitionUpdate update = null;
  2645.                     bool elementLocationPathApplies = locationPathApplies;
  2646.                     LocationUpdates recurseLocationUpdates = locationUpdates;
  2647.                     SectionUpdates recurseSectionUpdates = sectionUpdates;
  2648.                     bool recurseAddNewSections = addNewSections;
  2649.                     string recurseGroup = group;
  2650.                     bool removedSectionOrGroup = false;
  2651.                    
  2652.                     // update the lineposition and indent for each element
  2653.                     indent = UpdateIndent(indent, xmlUtil, utilWriter, parentLinePosition);
  2654.                     linePosition = xmlUtil.TrueLinePosition;
  2655.                    
  2656.                     string elementName = reader.Name;
  2657.                     if (elementName == KEYWORD_LOCATION) {
  2658.                         string locationSubPathAttribute = reader.GetAttribute(KEYWORD_LOCATION_PATH);
  2659.                         locationSubPathAttribute = NormalizeLocationSubPath(locationSubPathAttribute, xmlUtil);
  2660.                         elementLocationPathApplies = StringUtil.EqualsIgnoreCase(_locationSubPath, locationSubPathAttribute);
  2661.                         bool allowOverride = true;
  2662.                         bool inheritInChildApps = true;
  2663.                        
  2664.                         if (elementLocationPathApplies) {
  2665.                             // Retrieve allowOverride and InheritInChildApps
  2666.                             string allowOverrideAttribute = reader.GetAttribute(KEYWORD_LOCATION_ALLOWOVERRIDE);
  2667.                             if (allowOverrideAttribute != null) {
  2668.                                 allowOverride = Boolean.Parse(allowOverrideAttribute);
  2669.                             }
  2670.                            
  2671.                             string inheritInChildAppsAttribute = reader.GetAttribute(KEYWORD_LOCATION_INHERITINCHILDAPPLICATIONS);
  2672.                             if (inheritInChildAppsAttribute != null) {
  2673.                                 inheritInChildApps = Boolean.Parse(inheritInChildAppsAttribute);
  2674.                             }
  2675.                            
  2676.                             // Flag that we already have one of these locations
  2677.                             configDefinitionUpdates.FlagLocationWritten();
  2678.                         }
  2679.                        
  2680.                         if (reader.IsEmptyElement) {
  2681.                             if (elementLocationPathApplies && (configDefinitionUpdates.FindLocationUpdates(allowOverride, inheritInChildApps) != null)) {
  2682.                                 // If we are going to make updates here, then
  2683.                                 // delete the one that is here (so we can update later)
  2684.                                 elementLocationPathApplies = true;
  2685.                             }
  2686.                             else {
  2687.                                 // If not lets leave it
  2688.                                 elementLocationPathApplies = false;
  2689.                             }
  2690.                         }
  2691.                         else {
  2692.                             // recurse if this location applies to us
  2693.                             if (elementLocationPathApplies) {
  2694.                                 if (configDefinitionUpdates != null) {
  2695.                                     recurseLocationUpdates = configDefinitionUpdates.FindLocationUpdates(allowOverride, inheritInChildApps);
  2696.                                     if (recurseLocationUpdates != null) {
  2697.                                         recurse = true;
  2698.                                         recurseSectionUpdates = recurseLocationUpdates.SectionUpdates;
  2699.                                        
  2700.                                         // If this is <location path=".">, we don't want to add moved sections
  2701.                                         // to it.
  2702.                                         if (_locationSubPath == null && recurseLocationUpdates.IsDefault) {
  2703.                                             recurseAddNewSections = false;
  2704.                                         }
  2705.                                     }
  2706.                                 }
  2707.                             }
  2708.                             else {
  2709.                                 // recurse if necessary to remove items in _removedSections and _removedGroups
  2710.                                 if (HasRemovedSectionsOrGroups && !IsLocationConfig && Host.SupportsLocation) {
  2711.                                     recurse = true;
  2712.                                     recurseLocationUpdates = null;
  2713.                                     recurseSectionUpdates = null;
  2714.                                     recurseAddNewSections = false;
  2715.                                 }
  2716.                             }
  2717.                         }
  2718.                     }
  2719.                     else {
  2720.                         string configKey = CombineConfigKey(group, elementName);
  2721.                         FactoryRecord factoryRecord = FindFactoryRecord(configKey, false);
  2722.                         if (factoryRecord == null) {
  2723.                             // The factory was deleted, so regardless of whether this is a
  2724.                             // section or sectionGroup, it can be skipped.
  2725.                             if (!elementLocationPathApplies && !IsLocationConfig) {
  2726.                                 removedSectionOrGroup = true;
  2727.                             }
  2728.                         }
  2729.                         else if (factoryRecord.IsGroup) {
  2730.                             if (reader.IsEmptyElement) {
  2731.                                 if (!elementLocationPathApplies && !IsLocationConfig) {
  2732.                                     removedSectionOrGroup = true;
  2733.                                 }
  2734.                             }
  2735.                             else {
  2736.                                 // if the location path applies, recurse if there are updates
  2737.                                 if (sectionUpdates != null) {
  2738.                                     SectionUpdates sectionUpdatesChild = sectionUpdates.GetSectionUpdatesForGroup(elementName);
  2739.                                     if (sectionUpdatesChild != null) {
  2740.                                         recurse = true;
  2741.                                         recurseGroup = configKey;
  2742.                                         recurseSectionUpdates = sectionUpdatesChild;
  2743.                                     }
  2744.                                 }
  2745.                                 else if (!elementLocationPathApplies && !IsLocationConfig) {
  2746.                                     if (_removedSectionGroups != null && _removedSectionGroups.Contains(configKey)) {
  2747.                                         removedSectionOrGroup = true;
  2748.                                     }
  2749.                                     else {
  2750.                                         recurse = true;
  2751.                                         recurseGroup = configKey;
  2752.                                         recurseLocationUpdates = null;
  2753.                                         recurseSectionUpdates = null;
  2754.                                         recurseAddNewSections = false;
  2755.                                     }
  2756.                                 }
  2757.                             }
  2758.                         }
  2759.                         else {
  2760.                             // it is a section - get the update
  2761.                             if (sectionUpdates != null) {
  2762.                                 update = sectionUpdates.GetDefinitionUpdate(configKey);
  2763.                             }
  2764.                             else if (!elementLocationPathApplies && !IsLocationConfig) {
  2765.                                 if (_removedSections != null && _removedSections.Contains(configKey)) {
  2766.                                     removedSectionOrGroup = true;
  2767.                                 }
  2768.                             }
  2769.                         }
  2770.                     }
  2771.                    
  2772.                     if (recurse) {
  2773.                         #if DBG
  2774.                         string startElementName = reader.Name;
  2775.                         #endif
  2776.                        
  2777.                         // flush, and get length of underlying stream
  2778.                         object checkpoint = utilWriter.CreateStreamCheckpoint();
  2779.                        
  2780.                         // Copy this element node and up to the first subelement
  2781.                         xmlUtil.CopyXmlNode(utilWriter);
  2782.                         xmlUtil.CopyReaderToNextElement(utilWriter, true);
  2783.                        
  2784.                         // Recurse
  2785.                         bool recurseWroteASection = CopyConfigDefinitionsRecursive(configDefinitionUpdates, xmlUtil, utilWriter, elementLocationPathApplies, recurseLocationUpdates, recurseSectionUpdates, recurseAddNewSections, recurseGroup, linePosition, indent
  2786.                         );
  2787.                        
  2788.                         // Copy the end element
  2789.                         xmlUtil.CopyXmlNode(utilWriter);
  2790.                        
  2791.                         if (recurseWroteASection) {
  2792.                             wroteASection = true;
  2793.                         }
  2794.                         else {
  2795.                             // back out the change
  2796.                             utilWriter.RestoreStreamCheckpoint(checkpoint);
  2797.                         }
  2798.                        
  2799.                         // Copy up to the next element, or exit this level.
  2800.                         xmlUtil.CopyReaderToNextElement(utilWriter, true);
  2801.                     }
  2802.                     else {
  2803.                         bool skip;
  2804.                         if (update == null) {
  2805.                             // remove the section from the file if we're in the correct location,
  2806.                             // or if the section or group should be removed from all locations
  2807.                             skip = elementLocationPathApplies || removedSectionOrGroup;
  2808.                         }
  2809.                         else {
  2810.                             // replace the section if the xml for it has been updated
  2811.                             // if it is a configSource, don't write it unless the configSource parameters have changed
  2812.                             skip = false;
  2813.                             if (update.UpdatedXml != null) {
  2814.                                 ConfigurationSection configSection = (ConfigurationSection)update.SectionRecord.Result;
  2815.                                 if (String.IsNullOrEmpty(configSection.SectionInformation.ConfigSource) || configSection.SectionInformation.ConfigSourceModified) {
  2816.                                     skip = true;
  2817.                                     WriteSectionUpdate(utilWriter, update, linePosition, indent, true);
  2818.                                     wroteASection = true;
  2819.                                 }
  2820.                             }
  2821.                         }
  2822.                        
  2823.                         if (skip) {
  2824.                             //
  2825.                             // Skip over the existing element, then
  2826.                             // copy up to the next element, or exit this level.
  2827.                             //
  2828.                             xmlUtil.SkipAndCopyReaderToNextElement(utilWriter, true);
  2829.                         }
  2830.                         else {
  2831.                             // Copy this entire contents of this element and then to the next element, or exit this level.
  2832.                             xmlUtil.CopyOuterXmlToNextElement(utilWriter, true);
  2833.                             wroteASection = true;
  2834.                         }
  2835.                     }
  2836.                 }
  2837.             }
  2838.            
  2839.             //
  2840.             // Write new section groups
  2841.             //
  2842.             if (sectionUpdates != null && addNewSections && sectionUpdates.HasNewSectionGroups()) {
  2843.                 // Add whitespace to align us with the other elements in this group
  2844.                 linePosition = parentLinePosition + indent;
  2845.                 if (reader.NodeType == XmlNodeType.EndElement) {
  2846.                     if (utilWriter.IsLastLineBlank) {
  2847.                         startingLinePosition = xmlUtil.TrueLinePosition;
  2848.                     }
  2849.                     else {
  2850.                         startingLinePosition = parentLinePosition;
  2851.                     }
  2852.                 }
  2853.                 else {
  2854.                     startingLinePosition = 0;
  2855.                 }
  2856.                
  2857.                 utilWriter.AppendSpacesToLinePosition(linePosition);
  2858.                
  2859.                 bool wroteNewSection = WriteNewConfigDefinitionsRecursive(utilWriter, sectionUpdates, linePosition, indent, true);
  2860.                 if (wroteNewSection) {
  2861.                     wroteASection = true;
  2862.                 }
  2863.                
  2864.                 // Restore the whitespace of the end element
  2865.                 utilWriter.AppendSpacesToLinePosition(startingLinePosition);
  2866.             }
  2867.            
  2868.             return wroteASection;
  2869.         }
  2870.        
  2871.         private void WriteSectionUpdate(XmlUtilWriter utilWriter, DefinitionUpdate update, int linePosition, int indent, bool skipFirstIndent)
  2872.         {
  2873.             ConfigurationSection configSection = (ConfigurationSection)update.SectionRecord.Result;
  2874.             string updatedXml;
  2875.            
  2876.             if (!String.IsNullOrEmpty(configSection.SectionInformation.ConfigSource)) {
  2877.                 updatedXml = string.Format(CultureInfo.InvariantCulture, FORMAT_SECTION_CONFIGSOURCE, configSection.SectionInformation.Name, configSection.SectionInformation.ConfigSource);
  2878.             }
  2879.             else {
  2880.                 updatedXml = update.UpdatedXml;
  2881.             }
  2882.            
  2883.             string formattedXml = XmlUtil.FormatXmlElement(updatedXml, linePosition, indent, skipFirstIndent);
  2884.             utilWriter.Write(formattedXml);
  2885.         }
  2886.        
  2887.         //
  2888.         // SaveConfigSource
  2889.         //
  2890.         private void SaveConfigSource(DefinitionUpdate update)
  2891.         {
  2892.            
  2893.             string configSourceStreamName;
  2894.            
  2895.             if (update.SectionRecord.HasResult) {
  2896.                 ConfigurationSection configSection = (ConfigurationSection)update.SectionRecord.Result;
  2897.                 configSourceStreamName = configSection.SectionInformation.ConfigSourceStreamName;
  2898.             }
  2899.             else {
  2900.                 Debug.Assert(update.SectionRecord.HasFileInput, "update.SectionRecord.HasFileInput");
  2901.                 SectionInput fileInput = update.SectionRecord.FileInput;
  2902.                 configSourceStreamName = fileInput.SectionXmlInfo.ConfigSourceStreamName;
  2903.             }
  2904.            
  2905.             // Copy the input stream before opening the output stream.
  2906.             byte[] readBuffer = null;
  2907.             using (Stream streamRead = Host.OpenStreamForRead(configSourceStreamName)) {
  2908.                 if (streamRead != null) {
  2909.                     readBuffer = new byte[streamRead.Length];
  2910.                     int count = streamRead.Read(readBuffer, 0, (int)streamRead.Length);
  2911.                     if (count != streamRead.Length) {
  2912.                         throw new ConfigurationErrorsException();
  2913.                     }
  2914.                 }
  2915.             }
  2916.            
  2917.             // Write the changes to the output stream.
  2918.             bool hasFile = (readBuffer != null);
  2919.             object writeContext = null;
  2920.             bool streamOpened = false;
  2921.            
  2922.             try {
  2923.                 try {
  2924.                     string templateStreamName;
  2925.                    
  2926.                     if (Host.IsRemote) {
  2927.                         // templateStreamName is used by OpenStreamForWrite for copying file attributes during saving.
  2928.                         // (for details, see WriteFileContext.Complete.)
  2929.                         //
  2930.                         // If we're using a remote host, then ConfigStreamInfo.StreamName is actually pointing to a
  2931.                         // full filepath on a remote machine. In this case, it's impossible to copy the attributes
  2932.                         // over, and thus we won't do it.
  2933.                         templateStreamName = null;
  2934.                     }
  2935.                     else {
  2936.                         templateStreamName = ConfigStreamInfo.StreamName;
  2937.                     }
  2938.                    
  2939.                     using (Stream streamWrite = Host.OpenStreamForWrite(configSourceStreamName, templateStreamName, ref writeContext)) {
  2940.                         streamOpened = true;
  2941.                         if (update.UpdatedXml == null) {
  2942.                             Debug.Assert(hasFile, "hasFile");
  2943.                             if (hasFile) {
  2944.                                 streamWrite.Write(readBuffer, 0, readBuffer.Length);
  2945.                             }
  2946.                         }
  2947.                         else {
  2948.                             using (StreamWriter streamWriter = new StreamWriter(streamWrite)) {
  2949.                                 XmlUtilWriter utilWriter = new XmlUtilWriter(streamWriter, true);
  2950.                                 if (hasFile) {
  2951.                                     CopyConfigSource(utilWriter, update.UpdatedXml, configSourceStreamName, readBuffer);
  2952.                                 }
  2953.                                 else {
  2954.                                     CreateNewConfigSource(utilWriter, update.UpdatedXml, DEFAULT_INDENT);
  2955.                                 }
  2956.                             }
  2957.                         }
  2958.                     }
  2959.                 }
  2960.                 catch {
  2961.                     if (streamOpened) {
  2962.                         Host.WriteCompleted(configSourceStreamName, false, writeContext);
  2963.                     }
  2964.                    
  2965.                     throw;
  2966.                 }
  2967.             }
  2968.             //
  2969.             // Guarantee that exceptions contain at least the name of the stream by wrapping them
  2970.             // in a ConfigurationException.
  2971.             //
  2972.             catch (Exception e) {
  2973.                 throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), e, configSourceStreamName, 0);
  2974.             }
  2975.             catch {
  2976.                 throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_error_loading_XML_file), null, configSourceStreamName, 0);
  2977.             }
  2978.            
  2979.             Host.WriteCompleted(configSourceStreamName, true, writeContext);
  2980.         }
  2981.        
  2982.         private void CopyConfigSource(XmlUtilWriter utilWriter, string updatedXml, string configSourceStreamName, byte[] buffer)
  2983.         {
  2984.             // only copy the byte order mark if it exists in the current web.config
  2985.             byte[] preamble;
  2986.             using (Stream stream = new MemoryStream(buffer)) {
  2987.                 using (XmlUtil xmlUtil = new XmlUtil(stream, configSourceStreamName, true)) {
  2988.                     preamble = ConfigStreamInfo.StreamEncoding.GetPreamble();
  2989.                 }
  2990.             }
  2991.            
  2992.             CheckPreamble(preamble, utilWriter, buffer);
  2993.            
  2994.             using (Stream stream = new MemoryStream(buffer)) {
  2995.                 using (XmlUtil xmlUtil = new XmlUtil(stream, configSourceStreamName, false)) {
  2996.                     XmlTextReader reader = xmlUtil.Reader;
  2997.                    
  2998.                     // copy up to the first element
  2999.                     reader.WhitespaceHandling = WhitespaceHandling.All;
  3000.                     reader.Read();
  3001.                    
  3002.                     // determine the indent to use for the element
  3003.                     int indent = DEFAULT_INDENT;
  3004.                     int linePosition = 1;
  3005.                     bool hasElement = xmlUtil.CopyReaderToNextElement(utilWriter, false);
  3006.                     if (hasElement) {
  3007.                         // find the indent of the first attribute, if any
  3008.                         int lineNumber = reader.LineNumber;
  3009.                         linePosition = reader.LinePosition - 1;
  3010.                         int attributeIndent = 0;
  3011.                         while (reader.MoveToNextAttribute()) {
  3012.                             if (reader.LineNumber > lineNumber) {
  3013.                                 attributeIndent = reader.LinePosition - linePosition;
  3014.                                 break;
  3015.                             }
  3016.                         }
  3017.                        
  3018.                         // find the indent of the first sub element, if any
  3019.                         int elementIndent = 0;
  3020.                         reader.Read();
  3021.                         while (reader.Depth >= 1) {
  3022.                             if (reader.NodeType == XmlNodeType.Element) {
  3023.                                 elementIndent = (reader.LinePosition - 1) - linePosition;
  3024.                                 break;
  3025.                             }
  3026.                            
  3027.                             reader.Read();
  3028.                         }
  3029.                        
  3030.                         if (elementIndent > 0) {
  3031.                             indent = elementIndent;
  3032.                         }
  3033.                         else if (attributeIndent > 0) {
  3034.                             indent = attributeIndent;
  3035.                         }
  3036.                     }
  3037.                    
  3038.                     // Write the config source
  3039.                     string formattedXml = XmlUtil.FormatXmlElement(updatedXml, linePosition, indent, true);
  3040.                     utilWriter.Write(formattedXml);
  3041.                    
  3042.                     // Copy remaining contents
  3043.                     if (hasElement) {
  3044.                         // Skip over the existing element
  3045.                         while (reader.Depth > 0) {
  3046.                             reader.Read();
  3047.                         }
  3048.                        
  3049.                         if (reader.IsEmptyElement || reader.NodeType == XmlNodeType.EndElement) {
  3050.                             reader.Read();
  3051.                         }
  3052.                        
  3053.                         // Copy remainder of file
  3054.                         while (xmlUtil.CopyXmlNode(utilWriter)) {
  3055.                         }
  3056.                     }
  3057.                 }
  3058.             }
  3059.         }
  3060.        
  3061.        
  3062.         private void CreateNewConfigSource(XmlUtilWriter utilWriter, string updatedXml, int indent)
  3063.         {
  3064.             string formattedXml = XmlUtil.FormatXmlElement(updatedXml, 0, indent, true);
  3065.             utilWriter.Write(string.Format(CultureInfo.InvariantCulture, FORMAT_CONFIGSOURCE_FILE, ConfigStreamInfo.StreamEncoding.WebName));
  3066.             utilWriter.Write(formattedXml + NL);
  3067.         }
  3068.        
  3069.         private static string BoolToString(bool v)
  3070.         {
  3071.             return v ? KEYWORD_TRUE : KEYWORD_FALSE;
  3072.         }
  3073.        
  3074.         // RemoveLocationWriteRequirement
  3075.         //
  3076.         // It is possible that we have set the flag to force this location
  3077.         // to be written out. Allow a way to remove that
  3078.         //
  3079.         internal void RemoveLocationWriteRequirement()
  3080.         {
  3081.             if (IsLocationConfig) {
  3082.                 _flags[ForceLocationWritten] = false;
  3083.                 _flags[SuggestLocationRemoval] = true;
  3084.             }
  3085.         }
  3086.        
  3087.         // NamespacePresent
  3088.         //
  3089.         // Is the namespace present in the file or not? ...and do you
  3090.         // want it to be?
  3091.         //
  3092.         internal bool NamespacePresent {
  3093.             get { return _flags[NamespacePresentCurrent]; }
  3094.             set { _flags[NamespacePresentCurrent] = value; }
  3095.         }
  3096.        
  3097.         // NamespaceChangeNeeded
  3098.         //
  3099.         // On Update, do we need to add the namespace, remove it, or do nothing?
  3100.         //
  3101.         private NamespaceChange NamespaceChangeNeeded {
  3102.             get {
  3103.                 if (_flags[NamespacePresentCurrent] == _flags[NamespacePresentInFile]) {
  3104.                     return NamespaceChange.None;
  3105.                 }
  3106.                
  3107.                 if (_flags[NamespacePresentCurrent]) {
  3108.                     return NamespaceChange.Add;
  3109.                 }
  3110.                
  3111.                 return NamespaceChange.Remove;
  3112.             }
  3113.         }
  3114.        
  3115.         // RecordItselfRequiresUpdates
  3116.         //
  3117.         // Outside the scope of the sections and there definitions, does
  3118.         // the record itself require an update.
  3119.         //
  3120.         private bool RecordItselfRequiresUpdates {
  3121.             get { return (NamespaceChangeNeeded != NamespaceChange.None); }
  3122.         }
  3123.     }
  3124. }

Developer Fusion