简体   繁体   English

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

[英]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: 我需要在运行时修改app.config<configuration><system.diagnostics>部分,以便我可以:

  1. add a CustomTraceListener under the <sharedListeners> element, which requires special initializeData that can only be ascertained at runtime. <sharedListeners>元素下添加一个CustomTraceListener ,这需要特殊的initializeData ,只能在运行时确定。

  2. add the CustomTraceListener shared listener to an existing source under the <source><listeners> element. CustomTraceListener共享侦听器添加到<source><listeners>元素下的现有源。

  3. persist the CustomTraceListener to other assemblies which load their trace source and listener configurations from the config file. CustomTraceListener持久CustomTraceListener到其他程序集,这些程序集从配置文件加载其跟踪源和侦听器配置。

The relevant sections in app.config looks something like this presently: 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>

Using ConfigurationManager I can easily do: 使用ConfigurationManager我可以轻松地做到:

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

And when I do this, diagnostics is a System.Diagnostics.SystemDiagnosticsSection type. 当我这样做时, diagnosticsSystem.Diagnostics.SystemDiagnosticsSection类型。 Interestingly I can't cast diagnostics to a SystemDiagnosticsSection type because I can't find it within any namespace. 有趣的是,我无法将diagnostics转换为SystemDiagnosticsSection类型,因为我无法在任何命名空间中找到它。 Regardless, ConfigurationSection doesn't seem to have any methods that I can use to write data into the section. 无论如何, ConfigurationSection似乎没有任何方法可以用来将数据写入该部分。

I also can't cast it to a NameValueConfigurationCollection because diagnostics base type is ConfigurationSection . 我也无法将其转换为NameValueConfigurationCollection因为diagnostics基类型是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? 我是否必须恢复使用普通的XML来实现这一目标? I really don't like reinventing the wheel. 我真的不喜欢重新发明轮子。

You can locate the path to the app.exe.config file through the ConfigurationManager , then load the config file as an XDocument . 您可以通过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

Once the required changes are made, save the XDocument back to disk, and call Trace.Refresh() to reload the trace configuration. 完成所需的更改后,将XDocument保存回磁盘,并调用Trace.Refresh()以重新加载跟踪配置。

See MSDN regarding the Trace.Refresh method here . 有关Trace.Refresh方法,请参阅MSDN

For experience i would warn you to make app.config changes from application if the app is deployed with a good install procedure under protected directories, eg. 对于经验,如果应用程序在受保护目录下部署了良好的安装过程,我会警告您从应用程序进行app.config更改,例如。 Program files in MS OS with UAC activated. MS OS中的程序文​​件已激活UAC。

To update config files sometimes you need some admin privileges. 要更新配置文件,有时您需要一些管理员权限。

The Bad thing is than all run correctly under visual studio / debug or some test procedure, after deploy, in production,you may have some issue... 糟糕的事情是在视觉工作室/调试或某些测试程序下正确运行,在部署之后,在生产中,您可能会遇到一些问题......

If you make direct changes to the <configuration><system.diagnostics> section of the app.config file at run time, the app needs to be restarted or Trace.Refresh() must be called to have the changes take effect. 如果在运行时直接更改app.config文件的<configuration><system.diagnostics>部分,则需要重新启动应用程序或必须调用Trace.Refresh()才能使更改生效。

Another option is to programmatically add TraceListeners at application start-up, eg Trace.Listeners.Add(new TextWriterTraceListener("output.log", "myListener")); 另一种选择是在应用程序启动时以编程方式添加TraceListeners,例如Trace.Listeners.Add(new TextWriterTraceListener("output.log", "myListener"));

see https://msdn.microsoft.com/en-us/library/sk36c28t(v=vs.110).aspx . 请参阅https://msdn.microsoft.com/en-us/library/sk36c28t(v=vs.110).aspx

To add a filter with the initializeData value as in your question you can use the TraceListener.Filter property 要在问题中添加具有initializeData值的过滤器,可以使用TraceListener.Filter属性

To share settings across applications you can use the configSource property on the <system.diagnostics> element and put that element in a separate config file. 要跨应用程序共享设置,可以使用<system.diagnostics>元素上的configSource属性,并将该元素放在单独的配置文件中。 The downside of this is that the file needs to be in the same folder as the app.config. 这样做的缺点是该文件需要与app.config位于同一文件夹中。 So a change to one file would either need to be copied and pasted to other locations or shared in some other way. 因此,对一个文件的更改要么需要复制并粘贴到其他位置,要么以其他方式共享。

An alternative would be to save a custom config file containing the trace listener information at a location all apps can access and then in each app load the file at start-up and configure the trace listeners as above. 另一种方法是在所有应用程序可以访问的位置保存包含跟踪侦听器信息的自定义配置文件,然后在每个应用程序中启动时加载文件并按上述方式配置跟踪侦听器。


Update 更新

To share logging throughout your application you could create a class that implements the singleton pattern to return your TraceSource instance or to wrap your logging activities. 要在整个应用程序中共享日志记录,您可以创建一个实现单例模式的类,以返回TraceSource实例或包装日志记录活动。 This way you don't have to pass round the same instance 这样您就不必传递相同的实例

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");

You could extend this to then encapsulate the actual messages you want to log so that the code doing the logging doesn't know the specifics and you have just one place where your events are defined, eg 您可以对此进行扩展,然后封装您要记录的实际消息,以便执行日志记录的代码不知道具体内容,并且您只有一个位置可以定义事件,例如

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM