在运行时修改 app.config 部分

本文关键字:system diagnostics 部分 config 运行时 修改 app | 更新日期: 2023-09-27 18:36:04

我需要在运行时修改app.config<configuration><system.diagnostics>部分,以便我可以:

  1. <sharedListeners> 元素下添加一个CustomTraceListener,这需要只能在运行时确定的特殊initializeData

  2. CustomTraceListener共享侦听器添加到 <source><listeners> 元素下的现有源。

  3. CustomTraceListener保存到从配置文件加载其跟踪源和侦听器配置的其他程序集。

app.config中的相关部分目前如下所示:

<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>

使用ConfigurationManager我可以轻松做到:

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

当我这样做时,diagnostics是一种System.Diagnostics.SystemDiagnosticsSection类型。 有趣的是,我无法将diagnostics转换为SystemDiagnosticsSection类型,因为我无法在任何命名空间中找到它。无论如何,ConfigurationSection似乎没有任何可用于将数据写入该部分的方法。

我也无法将其转换为NameValueConfigurationCollection diagnostics因为基本类型是ConfigurationSection.我听说过这种技术,但似乎我不能使用它。

我是否必须恢复使用普通的旧 XML 来完成此操作? 我真的不喜欢重新发明轮子。

在运行时修改 app.config <system.diagnostics> 部分

可以通过ConfigurationManager找到app.exe.config文件的路径,然后将配置文件作为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

进行所需的更改后,将XDocument保存回磁盘,并调用Trace.Refresh()以重新加载跟踪配置。

请参阅此处有关Trace.Refresh方法的 MSDN。

为了获得经验,我会警告您,如果应用程序是在受保护的目录下使用良好的安装过程部署的,请从应用程序进行 app.config 更改,例如。在激活了UAC的MS操作系统中编程文件。

要更新配置文件,有时您需要一些管理员权限。

不好的是,在视觉工作室/调试或某些测试程序下,所有正确运行,部署后,在生产中,您可能会遇到一些问题......

如果直接更改<configuration><system.diagnostics>部分,app.config运行时,需要重新启动应用或必须调用Trace.Refresh()才能使更改生效。

另一种选择是在应用程序启动时以编程方式添加 TraceListener,例如 Trace.Listeners.Add(new TextWriterTraceListener("output.log", "myListener"));

请参阅 https://msdn.microsoft.com/en-US/library/SK36C28T(v=vs.110).aspx。

要添加具有问题中initializeData值的过滤器,您可以使用 TraceListener.Filter 属性

若要在应用程序之间共享设置,可以使用 <system.diagnostics> 元素上的 configSource 属性,并将该元素放在单独的配置文件中。这样做的缺点是文件需要与 app.config 位于同一文件夹中。因此,对一个文件的更改需要复制并粘贴到其他位置或以其他方式共享。

另一种方法是将包含跟踪侦听器信息的自定义配置文件保存在所有应用都可以访问的位置,然后在每个应用中在启动时加载该文件并如上所述配置跟踪侦听器。


更新

若要在整个应用程序中共享日志记录,可以创建一个实现单一实例模式的类,以返回TraceSource实例或包装日志记录活动。这样,您就不必传递相同的实例

public class Logger
{
    private static Logger _logger;
        private TraceSource _ts;
        private Logger()
        {
        // Configure TraceSource here as required, e.g.
            _ts = new TraceSource("StackOverflow", SourceLevels.All);
            _ts.Listeners.Add(new TextWriterTraceListener(@"c:'temp'tracefile.log"));
        }
        public static Logger Get()
        {
            if (_logger == null)
            {
                _logger = new Logger();
            }
            return _logger;
        }
        public void TraceInfo(string message)
        {
            _ts.TraceInformation(message);
            _ts.Flush();
        }
}
// To use
Logger.Get().TraceInfo("This is a trace message");

您可以将其扩展为封装要记录的实际消息,以便执行日志记录的代码不知道细节,并且您只有一个定义事件的位置,例如

public void TraceApplicationStarting()
{
    _ts.TraceEvent(TraceEventType.Verbose, 1, "Application Starting");
}