Search code examples
c#.netconfigurationapp-configconfigurationmanager

Modify app.config <system.diagnostics> section at runtime


I need to modify the <configuration><system.diagnostics> section of an app.config at runtime so that I can:

  1. add a CustomTraceListener under the <sharedListeners> element, which requires special initializeData that can only be ascertained at runtime.

  2. add the CustomTraceListener shared listener to an existing source under the <source><listeners> element.

  3. persist the CustomTraceListener to other assemblies which load their trace source and listener configurations from the config file.

The relevant sections in app.config looks something like this presently:

<system.diagnostics>
  <sources>
    <source name="mysource" switchName="..." switchType="...">
      <listeners>
        <add name="console" />
        <add name="customtracelistener" /> /// need to add new listener here
      </listeners>
    </source>
  </sources>
  <sharedListeners>  
    <add name="console" type="..." initializeData="..." />
    <add name="customtracelistener" type="..." initializeData="..."> /// need to add custom trace listener here 
      <filter type="..." initializeData="Warning"/> /// with a filter
    </add>
  </sharedListeners>
  <switches>
    <add name="..." value="..." />
  </switches>
</system.diagnostics>

Using ConfigurationManager I can easily do:

Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConfigurationSection diagnostics = config.GetSection("system.diagnostics");

And when I do this, diagnostics is a System.Diagnostics.SystemDiagnosticsSection type. Interestingly I can't cast diagnostics to a SystemDiagnosticsSection type because I can't find it within any namespace. Regardless, ConfigurationSection doesn't seem to have any methods that I can use to write data into the section.

I also can't cast it to a NameValueConfigurationCollection because diagnostics base type is ConfigurationSection. I heard about this technique but it seems I can't use it.

Do I have to revert to using plain-old XML to accomplish this? I really don't like reinventing the wheel.


Solution

  • You can locate the path to the app.exe.config file through the ConfigurationManager, then load the config file as an XDocument.

    string configPath = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;
    
    XDocument config = XDocument.Load(configPath);
    XElement diagnostics = config.Descendants().FirstOrDefault(e => e.Name == "system.diagnostics");
    
    if (diagnostics == default(XElement))
    {
        /// <system.diagnostics> element was not found in config
    }
    else
    {
        /// make changes within <system.diagnostics> here...
    }
    
    config.Save(configPath);
    
    Trace.Refresh();  /// reload the trace configuration
    

    Once the required changes are made, save the XDocument back to disk, and call Trace.Refresh() to reload the trace configuration.

    See MSDN regarding the Trace.Refresh method here.