3

Microsoft gives instructions for how to use the file attribute to make a .config file's appSettings section reference another file: For example:

<appSettings file="c:\commonSettings.config">
    <add key="myAppSpecificSetting" value="Setting1" />
</appSettings>

However, this is implemented specifically for only appSettings and isn't some general .config file feature.

Now, I have implemented my own ConfigurationSection, and would like to be able to specify file= just like one can with appSettings. Aside from simply creating the property to match the attribute and retrieve the file name, how can I actually recreate/simulate this functionality in my custom configSection?

ErikE
  • 48,881
  • 23
  • 151
  • 196

1 Answers1

1

Thankfully we have the source code now. It looks like it's just something implemented by AppSettingsSection by reading the file system, nothing special you can reuse in your own configuration section.

protected internal override void DeserializeElement(XmlReader reader, bool serializeCollectionKey) 
{
    string ElementName = reader.Name;

    base.DeserializeElement(reader, serializeCollectionKey);
    if ((File != null) && (File.Length > 0)) {
        string sourceFileFullPath;
        string configFileDirectory;
        string configFile;

        // Determine file location
        configFile = ElementInformation.Source;

        if (String.IsNullOrEmpty(configFile)) {
            sourceFileFullPath = File;
        }
        else {
            configFileDirectory = System.IO.Path.GetDirectoryName(configFile);
            sourceFileFullPath = System.IO.Path.Combine(configFileDirectory, File);
        }

        if (System.IO.File.Exists(sourceFileFullPath)) {
            int lineOffset = 0;
            string rawXml = null;

            using (Stream sourceFileStream = new FileStream(sourceFileFullPath, FileMode.Open, FileAccess.Read, FileShare.Read)) {
                using (XmlUtil xmlUtil = new XmlUtil(sourceFileStream, sourceFileFullPath, true)) {
                    if (xmlUtil.Reader.Name != ElementName) {
                        throw new ConfigurationErrorsException(
                                SR.GetString(SR.Config_name_value_file_section_file_invalid_root, ElementName),
                                xmlUtil);
                    }

                    lineOffset = xmlUtil.Reader.LineNumber;
                    rawXml = xmlUtil.CopySection();

                    // Detect if there is any XML left over after the section
                    while (!xmlUtil.Reader.EOF) {
                        XmlNodeType t = xmlUtil.Reader.NodeType;
                        if (t != XmlNodeType.Comment) {
                            throw new ConfigurationErrorsException(SR.GetString(SR.Config_source_file_format), xmlUtil);
                        }

                        xmlUtil.Reader.Read();
                    }
                }
            }

            ConfigXmlReader internalReader = new ConfigXmlReader(rawXml, sourceFileFullPath, lineOffset);
            internalReader.Read();
            if (internalReader.MoveToNextAttribute()) {
                throw new ConfigurationErrorsException(SR.GetString(SR.Config_base_unrecognized_attribute, internalReader.Name), (XmlReader)internalReader);
            }

            internalReader.MoveToElement();

            base.DeserializeElement(internalReader, serializeCollectionKey);
        }
    }
}
Jacob
  • 77,566
  • 24
  • 149
  • 228
  • I saw that method (see the link to the source code in my question) but didn't know it was involved (I see the `File` property reference now, though). When does DeserializeElement get called? – ErikE Feb 29 '16 at 17:25
  • I'm not sure exactly, but I assume somewhere in the bowels of ConfigurationManager. – Jacob Feb 29 '16 at 17:26
  • Note to self: always look at the `override` methods in a class you're trying to understand, because they can connect custom functionality to base class functionality... – ErikE Feb 29 '16 at 17:27
  • Unfortunately, this doesn't really help. I can't duplicate the functionality because I can't override the `DeserializeElement` method in my own class... back to the drawing board. – ErikE Apr 14 '16 at 00:27