// Copy configuration sections from the original configuration file.
private bool CopyConfigDefinitionsRecursive(
ConfigDefinitionUpdates configDefinitionUpdates, XmlUtil xmlUtil, XmlUtilWriter utilWriter,
bool locationPathApplies, LocationUpdates locationUpdates, SectionUpdates sectionUpdates,
bool addNewSections, string group, int parentLinePosition, int parentIndent) {
bool wroteASection = false;
XmlTextReader reader = xmlUtil.Reader;
int linePosition;
int indent;
int startingLinePosition;
indent = UpdateIndent(parentIndent, xmlUtil, utilWriter, parentLinePosition);
if (reader.NodeType == XmlNodeType.Element) {
linePosition = xmlUtil.TrueLinePosition;
startingLinePosition = linePosition;
}
else if (reader.NodeType == XmlNodeType.EndElement) {
linePosition = parentLinePosition + indent;
if (utilWriter.IsLastLineBlank) {
startingLinePosition = xmlUtil.TrueLinePosition;
}
else {
startingLinePosition = parentLinePosition;
}
}
else {
linePosition = parentLinePosition + indent;
startingLinePosition = 0;
}
//
// Write any new sections that apply to this group
//
if (sectionUpdates != null && addNewSections) {
// Remove newness, so we won't write again
sectionUpdates.IsNew = false;
Debug.Assert(locationPathApplies, "locationPathApplies");
string[] movedSectionNames = sectionUpdates.GetMovedSectionNames();
if (movedSectionNames != null) {
if (!utilWriter.IsLastLineBlank) {
utilWriter.AppendNewLine();
}
utilWriter.AppendSpacesToLinePosition(linePosition);
bool skipFirstIndent = true;
foreach (string configKey in movedSectionNames) {
DefinitionUpdate update = sectionUpdates.GetDefinitionUpdate(configKey);
WriteSectionUpdate(utilWriter, update, linePosition, indent, skipFirstIndent);
skipFirstIndent = false;
utilWriter.AppendNewLine();
wroteASection = true;
}
// Restore the whitespace we used for the first element, which is either a start or an end element.
utilWriter.AppendSpacesToLinePosition(startingLinePosition);
}
}
if (reader.NodeType == XmlNodeType.Element) {
//
// For each element at this depth, either:
// - Write the element verbatim and recurse due to a location section or group hierarchy element.
// - Write the element verbatim because it is unchanged, or because the current location does
// not apply.
// - Write the updated XML for the section.
// - Skip it because the section has been removed.
//
int depth = reader.Depth;
while (reader.Depth == depth) {
bool recurse = false;
DefinitionUpdate update = null;
bool elementLocationPathApplies = locationPathApplies;
LocationUpdates recurseLocationUpdates = locationUpdates;
SectionUpdates recurseSectionUpdates = sectionUpdates;
bool recurseAddNewSections = addNewSections;
string recurseGroup = group;
bool removedSectionOrGroup = false;
// update the lineposition and indent for each element
indent = UpdateIndent(indent, xmlUtil, utilWriter, parentLinePosition);
linePosition = xmlUtil.TrueLinePosition;
string elementName = reader.Name;
if (elementName == KEYWORD_LOCATION) {
string locationSubPathAttribute = reader.GetAttribute(KEYWORD_LOCATION_PATH);
locationSubPathAttribute = NormalizeLocationSubPath(locationSubPathAttribute, xmlUtil);
elementLocationPathApplies = false;
OverrideModeSetting overrideMode = OverrideModeSetting.LocationDefault;
bool inheritInChildApps = true;
if (IsLocationConfig) {
// For location config we will compare config paths instead of location strings
// so that we dont end up comparing "1" with "Default Web Site" and ending up with the wrong result
if (locationSubPathAttribute == null) {
elementLocationPathApplies = false;
}
else {
elementLocationPathApplies = StringUtil.EqualsIgnoreCase(ConfigPath, Host.GetConfigPathFromLocationSubPath(Parent.ConfigPath, locationSubPathAttribute));
}
}
else {
Debug.Assert(LocationSubPath == null);
// This is the same as doing StringUtil.EqualsIgnoreCase(_locationSubPath, locationSubPathAttribute)
// but remember the first one is null. Also remember locationSubPathAttribute is already normalized
elementLocationPathApplies = (locationSubPathAttribute == null);
}
if (elementLocationPathApplies) {
// Retrieve overrideMode and InheritInChildApps
string allowOverrideAttribute = reader.GetAttribute(KEYWORD_LOCATION_ALLOWOVERRIDE);
if (allowOverrideAttribute != null) {
overrideMode = OverrideModeSetting.CreateFromXmlReadValue(Boolean.Parse(allowOverrideAttribute));
}
string overrideModeAttribute = reader.GetAttribute(KEYWORD_LOCATION_OVERRIDEMODE);
if (overrideModeAttribute != null) {
overrideMode = OverrideModeSetting.CreateFromXmlReadValue(OverrideModeSetting.ParseOverrideModeXmlValue(overrideModeAttribute, null));
Debug.Assert(allowOverrideAttribute == null, "allowOverride and overrideMode both detected in a <location> tag");
}
string inheritInChildAppsAttribute = reader.GetAttribute(KEYWORD_LOCATION_INHERITINCHILDAPPLICATIONS);
if (inheritInChildAppsAttribute != null) {
inheritInChildApps = Boolean.Parse(inheritInChildAppsAttribute);
}
// Flag that we already have one of these locations
configDefinitionUpdates.FlagLocationWritten();
}
if (reader.IsEmptyElement) {
if (elementLocationPathApplies &&
(configDefinitionUpdates.FindLocationUpdates(overrideMode,
inheritInChildApps) != null)) {
// If we are going to make updates here, then
// delete the one that is here (so we can update later)
elementLocationPathApplies = true;
}
else {
// If not lets leave it
elementLocationPathApplies = false;
}
}
else {
// recurse if this location applies to us
if (elementLocationPathApplies) {
if (configDefinitionUpdates != null) {
recurseLocationUpdates = configDefinitionUpdates.FindLocationUpdates(overrideMode, inheritInChildApps);
if (recurseLocationUpdates != null) {
recurse = true;
recurseSectionUpdates = recurseLocationUpdates.SectionUpdates;
// If this is <location path=".">, we don't want to add moved sections
// to it.
if (_locationSubPath == null && recurseLocationUpdates.IsDefault) {
recurseAddNewSections = false;
}
}
}
}
else {
// recurse if necessary to remove items in _removedSections and _removedGroups
if (HasRemovedSectionsOrGroups && !IsLocationConfig && Host.SupportsLocation) {
recurse = true;
recurseLocationUpdates = null;
recurseSectionUpdates = null;
recurseAddNewSections = false;
}
}
}
}
else {
string configKey = CombineConfigKey(group, elementName);
FactoryRecord factoryRecord = FindFactoryRecord(configKey, false);
if (factoryRecord == null) {
// The factory was deleted, so regardless of whether this is a
// section or sectionGroup, it can be skipped.
if (!elementLocationPathApplies && !IsLocationConfig) {
removedSectionOrGroup = true;
}
}
else if (factoryRecord.IsGroup) {
if (reader.IsEmptyElement) {
if (!elementLocationPathApplies && !IsLocationConfig) {
removedSectionOrGroup = true;
}
}
else {
// if the location path applies, recurse if there are updates
if (sectionUpdates != null) {
SectionUpdates sectionUpdatesChild = sectionUpdates.GetSectionUpdatesForGroup(elementName);
if (sectionUpdatesChild != null) {
recurse = true;
recurseGroup = configKey;
recurseSectionUpdates = sectionUpdatesChild;
}
}
else if (!elementLocationPathApplies && !IsLocationConfig) {
if (_removedSectionGroups != null && _removedSectionGroups.Contains(configKey)) {
removedSectionOrGroup = true;
}
else {
recurse = true;
recurseGroup = configKey;
recurseLocationUpdates = null;
recurseSectionUpdates = null;
recurseAddNewSections = false;
}
}
}
}
else {
// it is a section - get the update
if (sectionUpdates != null) {
update = sectionUpdates.GetDefinitionUpdate(configKey);
}
else if (!elementLocationPathApplies && !IsLocationConfig) {
if (_removedSections != null && _removedSections.Contains(configKey)) {
removedSectionOrGroup = true;
}
}
}
}
if (recurse) {
#if DBG
string startElementName = reader.Name;
#endif
// flush, and get length of underlying stream
object checkpoint = utilWriter.CreateStreamCheckpoint();
// Copy this element node and up to the first subelement
xmlUtil.CopyXmlNode(utilWriter);
xmlUtil.CopyReaderToNextElement(utilWriter, true);
// Recurse
bool recurseWroteASection = CopyConfigDefinitionsRecursive(
configDefinitionUpdates, xmlUtil, utilWriter, elementLocationPathApplies, recurseLocationUpdates, recurseSectionUpdates,
recurseAddNewSections, recurseGroup, linePosition, indent);
// Copy the end element
xmlUtil.CopyXmlNode(utilWriter);
if (recurseWroteASection) {
wroteASection = true;
}
else {
// back out the change
utilWriter.RestoreStreamCheckpoint(checkpoint);
}
// Copy up to the next element, or exit this level.
xmlUtil.CopyReaderToNextElement(utilWriter, true);
}
else {
bool skip;
if (update == null) {
// remove the section from the file if we're in the correct location,
// or if the section or group should be removed from all locations
skip = elementLocationPathApplies || removedSectionOrGroup;
}
else {
// replace the section if the xml for it has been updated
// if it is a configSource, don't write it unless the configSource parameters have changed
skip = false;
if (update.UpdatedXml != null) {
ConfigurationSection configSection = (ConfigurationSection) update.SectionRecord.Result;
if ( String.IsNullOrEmpty(configSection.SectionInformation.ConfigSource) ||
configSection.SectionInformation.ConfigSourceModified) {
skip = true;
WriteSectionUpdate(utilWriter, update, linePosition, indent, true);
wroteASection = true;
}
}
}
if (skip) {
//
// Skip over the existing element, then
// copy up to the next element, or exit this level.
//
xmlUtil.SkipAndCopyReaderToNextElement(utilWriter, true);
}
else {
// Copy this entire contents of this element and then to the next element, or exit this level.
xmlUtil.CopyOuterXmlToNextElement(utilWriter, true);
wroteASection = true;
}
}
}
}
//
// Write new section groups
//
if (sectionUpdates != null && addNewSections && sectionUpdates.HasNewSectionGroups()) {
// Add whitespace to align us with the other elements in this group
linePosition = parentLinePosition + indent;
if (reader.NodeType == XmlNodeType.EndElement) {
if (utilWriter.IsLastLineBlank) {
startingLinePosition = xmlUtil.TrueLinePosition;
}
else {
startingLinePosition = parentLinePosition;
}
}
else {
startingLinePosition = 0;
}
utilWriter.AppendSpacesToLinePosition(linePosition);
bool wroteNewSection = WriteNewConfigDefinitionsRecursive(utilWriter, sectionUpdates, linePosition, indent, true);
if (wroteNewSection) {
wroteASection = true;
}
// Restore the whitespace of the end element
utilWriter.AppendSpacesToLinePosition(startingLinePosition);
}
return wroteASection;
}