// Gather all the updates to the configuration section declarations.
private SectionUpdates GetConfigDeclarationUpdates(ConfigurationSaveMode saveMode, bool forceUpdateAll) {
if (IsLocationConfig)
return null;
// hasChanged will be set to true if there is any change that will impact the current config file.
bool hasChanged = HasRemovedSectionsOrGroups;
SectionUpdates sectionUpdates = new SectionUpdates(string.Empty);
if (_factoryRecords != null) {
foreach (FactoryRecord factoryRecord in _factoryRecords.Values) {
if (!factoryRecord.IsGroup) {
string updatedXml = null;
// Never write out an undeclared section.
if (factoryRecord.IsUndeclared) {
continue;
}
// Note that GetConfigSection will return only those sections that have a sectionRecord
// and has a result. In another word, only sections that have been accessed.
ConfigurationSection configSection = GetConfigSection(factoryRecord.ConfigKey);
if (configSection != null) {
// We should skip this section declaration only if all below hold true:
// 1. The section should not be declared at this level. Reasons:
// i. The section is originally not declared at this level, or
// ii. The user calls SectionInformation.ForceDeclaration(false)
// 2. It's not machine.config. Otherwise we must declare it even if the user called ForceDeclaration(false)
// 3. It's already declared higher up.
// 4. It's not valid in the current Target Framework version
if (!configSection.SectionInformation.IsDeclared
&& !MgmtParent.IsRootConfig
&& MgmtParent.FindFactoryRecord(factoryRecord.ConfigKey, false) != null) {
if (factoryRecord.HasFile) {
hasChanged = true;
}
continue;
}
if (TargetFramework != null &&
!configSection.ShouldSerializeSectionInTargetVersion(TargetFramework))
{
continue;
}
if (AreDeclarationAttributesModified(factoryRecord, configSection) || !factoryRecord.HasFile) {
updatedXml = GetUpdatedSectionDeclarationXml(factoryRecord, configSection, saveMode);
if (!string.IsNullOrEmpty(updatedXml))
hasChanged = true;
}
}
DeclarationUpdate update = new DeclarationUpdate(factoryRecord.ConfigKey, !factoryRecord.HasFile, updatedXml);
sectionUpdates.AddSection(update);
}
else {
bool addGroupUpdate = false;
// LookupSectionGroup will return an object only if the group has been accessed
ConfigurationSectionGroup configSectionGroup = LookupSectionGroup(factoryRecord.ConfigKey);
if (!factoryRecord.HasFile) {
// Not in the file, so it means the group is added programmatically.
addGroupUpdate = true;
}
else if (configSectionGroup != null && configSectionGroup.IsDeclarationRequired) {
// The section group is declared in this config file
addGroupUpdate = true;
}
else if (factoryRecord.FactoryTypeName != null || configSectionGroup != null) {
FactoryRecord parentFactoryRecord = null;
if (!MgmtParent.IsRootConfig) {
parentFactoryRecord = MgmtParent.FindFactoryRecord(factoryRecord.ConfigKey, false);
}
// Add it if declaration is required. Please note this check is identical to the check
// for _declarationRequired in ConfigurationSectionGroup.AttachToConfigurationRecord.
addGroupUpdate = (parentFactoryRecord == null || parentFactoryRecord.FactoryTypeName == null);
}
if (addGroupUpdate) {
string updatedXml = null;
if (!factoryRecord.HasFile
|| (configSectionGroup != null && configSectionGroup.Type != factoryRecord.FactoryTypeName)) {
updatedXml = GetUpdatedSectionGroupDeclarationXml(factoryRecord, configSectionGroup);
if (!string.IsNullOrEmpty(updatedXml)) {
hasChanged = true;
}
}
Debug.Assert(!factoryRecord.IsUndeclared, "!factoryRecord.IsUndeclared");
Debug.Assert(!IsImplicitSection(factoryRecord.ConfigKey), "We should never write out an implicit section");
DeclarationUpdate update = new DeclarationUpdate(factoryRecord.ConfigKey, !factoryRecord.HasFile, updatedXml);
sectionUpdates.AddSectionGroup(update);
}
}
}
}
if (_sectionRecords != null) {
foreach (SectionRecord sectionRecord in _sectionRecords.Values) {
if (GetFactoryRecord(sectionRecord.ConfigKey, false) != null || !sectionRecord.HasResult) {
// Skip because this factory is defined locally ( in
// which case we handled above), or it was not used
continue;
}
ConfigurationSection configSection = (ConfigurationSection) sectionRecord.Result;
FactoryRecord factoryRecord = MgmtParent.FindFactoryRecord(sectionRecord.ConfigKey, false);
// Add this section declaration if:
// 1. The section is not declared locally (otherwise it's handled above)
// 2. SectionInformation.IsDeclared is true (i.e. user called SectionInformation.ForceDeclaration(true))
if (configSection.SectionInformation.IsDeclared) {
Debug.Assert(!IsImplicitSection(sectionRecord.ConfigKey), "We should never write out an implicit section");
Debug.Assert(!factoryRecord.IsUndeclared, "!factoryRecord.IsUndeclared");
string updatedXml = GetUpdatedSectionDeclarationXml(factoryRecord, configSection, saveMode);
if (!string.IsNullOrEmpty(updatedXml)) {
hasChanged = true;
DeclarationUpdate update = new DeclarationUpdate(factoryRecord.ConfigKey, true, updatedXml);
sectionUpdates.AddSection(update);
}
}
}
}
if (_sectionGroups != null) {
foreach (ConfigurationSectionGroup configSectionGroup in _sectionGroups.Values) {
if (GetFactoryRecord(configSectionGroup.SectionGroupName, false) != null) {
continue;
}
FactoryRecord factoryRecord = MgmtParent.FindFactoryRecord(configSectionGroup.SectionGroupName, false);
if ( configSectionGroup.IsDeclared ||
(factoryRecord != null && configSectionGroup.Type != factoryRecord.FactoryTypeName)) {
string updatedXml = GetUpdatedSectionGroupDeclarationXml(factoryRecord, configSectionGroup);
if (!string.IsNullOrEmpty(updatedXml)) {
hasChanged = true;
DeclarationUpdate update = new DeclarationUpdate(factoryRecord.ConfigKey, true, updatedXml);
sectionUpdates.AddSectionGroup(update);
}
}
}
}
if (hasChanged) {
return sectionUpdates;
}
else {
return null;
}
}