29

如何在 .net Windows 应用程序中动态重新加载 app.config?我需要动态地打开和关闭日志记录,而不仅仅是基于应用程序启动时的值。

ConfigurationManager.RefreshSection("appSettings") 不起作用,我也尝试使用 OpenExeConfiguration 显式打开配置文件,但我总是在应用程序启动时获得缓存值,而不是当前值。

我已经接受了创建自定义配置部分的答案。作为一个旁注和愚蠢的错误 - 如果您从 IDE 运行,那么更新 app.config 文件并期待更改是没有意义的。必须修改 bin\debug 文件夹中的 .exe.config 文件。嗬!

4

10 回答 10

25

您可以按照您所说的方式刷新自己的部分:

ConfigurationManager.RefreshSection("yoursection/subsection");

只需将记录真/假移动到一个部分,你会没事的。

于 2008-11-07T13:48:58.910 回答
7

如果您使用的是 log4Net,您可以按照您的要求进行操作:

尽管可以将 log4net 配置设置添加到项目app.configweb.config文件中,但最好将它们放在单独的配置文件中。除了可维护性的明显好处之外,它还有一个额外的好处,即 log4net 可以FileSystemWatcher在您的配置文件中放置一个对象以监控它何时更改并动态更新其设置。

要使用单独的配置文件,请将名为 Log4Net.config 的文件添加到您的项目中,并将以下属性添加到您的 AssemblyInfo.cs 文件中:

[assembly: log4net.Config.XmlConfigurator(ConfigFile="Log4Net.config", Watch = true)]

注意:对于 Web 应用程序,这假定Log4Net.config驻留在 Web 根目录中。确保log4net.config文件在属性中标记为“复制到输出”->“始终复制”。

于 2008-11-07T13:52:08.327 回答
7

以下是您可以使用的 hack,这将使配置从磁盘读取。

您只需要在修改模式下保存配置文件,然后刷新这将使应用程序重新从磁盘读取文件。

ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
于 2010-08-31T09:42:16.087 回答
2

请注意,在 WinForms 中,您可以在应用程序加载之前(之前Application.Start(new Form1()))对您的 app.config 进行编程更改,只要您使用System.Xml而不是System.Configuration.ConfigurationManager

string configFile = Application.ExecutablePath + ".config";  //c:\path\exename.exe.config
XmlDocument xdoc = new XmlDocument();
xdoc.Load(configFile);
XmlNode node = xdoc.SelectSingleNode("/configuration/appSettings/add[@key='nodeToChange']/@value");
node.Value = "new value";
File.WriteAllText(setFile, xdoc.InnerXml);
于 2009-04-14T16:55:51.810 回答
1

我编写了这个实现来在运行时更改日志级别并将新的阈值保留回 app.config(实际上是 Application.exe.config)。

界面:

internal interface ILoggingConfiguration
{
  void SetLogLevel(string level);

  string GetLogLevel();
}

实施:

internal sealed class LoggingConfigurationImpl : ILoggingConfiguration
{
  #region Members

  private static readonly ILog _logger = 
    ObjectManager.Common.Logger.GetLogger();
  private const string DEFAULT_NAME_SPACE = "Default.Name.Space";

  #endregion

  #region Implementation of ILoggingConfiguration

  public void SetLogLevel(string level)
  {
    Level threshold = Log4NetUtils.ConvertToLevel(level);
    ILoggerRepository[] repositories = LogManager.GetAllRepositories();

    foreach (ILoggerRepository repository in repositories)
    {
      try
      {
        SetLogLevelOnRepository(repository, threshold);
      }
      catch (Exception ex)
      {
        _logger.ErrorFormat("Exception while changing log-level: {0}", ex);
      }
    }
    PersistLogLevel(level);
  }

  public string GetLogLevel()
  {
    ILoggerRepository repository = LogManager.GetRepository();
    Hierarchy hierarchy = (Hierarchy) repository;
    ILogger logger = hierarchy.GetLogger(DEFAULT_NAME_SPACE);
    return ((Logger) logger).Level.DisplayName;
  }

  private void SetLogLevelOnRepository(ILoggerRepository repository,
                                       Level threshold)
  {
    repository.Threshold = threshold;
    Hierarchy hierarchy = (Hierarchy)repository;
    ILogger[] loggers = hierarchy.GetCurrentLoggers();
    foreach (ILogger logger in loggers)
    {
      try
      {
        SetLogLevelOnLogger(threshold, logger);
      }
      catch (Exception ex)
      {
        _logger.ErrorFormat("Exception while changing log-level for 
            logger: {0}{1}{2}", logger, Environment.NewLine, ex);
      }
    }
  }

  private void SetLogLevelOnLogger(Level threshold, ILogger logger)
  {
    ((Logger)logger).Level = threshold;
  }

  private void PersistLogLevel(string level)
  {
    XmlDocument config = new XmlDocument();
    config.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
    string xpath =
      String.Format("configuration/log4net/logger[@name='{0}']/level",
        DEFAULT_NAME_SPACE);
    XmlNode rootLoggerNode = config.SelectSingleNode(xpath);

    try
    {
      rootLoggerNode.Attributes["value"].Value = level;
      config.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

      ConfigurationManager.RefreshSection("log4net");
    }
    catch(Exception ex)
    {
      _logger.ErrorFormat("error while persisting new log-level: {0}", ex);
    }
  }

  #endregion
}

辅助类 Log4NetUtils:

public sealed class Log4NetUtils
{
  private static readonly ILoggerRepository _loggerRepository =
     LoggerManager.GetAllRepositories().First();

  public static Level ConvertToLevel(string level)
  {
    return _loggerRepository.LevelMap[level];
  }
}

XAML 代码:

<ComboBox Name="cbxLogLevel" Text="{Binding LogLevel}">
  <ComboBoxItem Content="DEBUG" />
  <ComboBoxItem Content="INFO" />
  <ComboBoxItem Content="WARN" />
  <ComboBoxItem Content="ERROR" />
</ComboBox>
<Button Name="btnChangeLogLevel" 
        Command="{Binding SetLogLevelCommand}"
        CommandParameter="{Binding ElementName=cbxLogLevel, Path=Text}" >
            Change log level
</Button>
于 2011-07-27T07:56:02.613 回答
0

我认为没有任何方法可以做到这一点,除非您使用 XML 编写自己的配置文件阅读器。为什么不根据配置文件设置在应用程序启动时打开或关闭日志记录,然后在程序运行时动态打开或关闭它?

于 2008-11-07T13:46:31.193 回答
0

我想我在 log4net 文档中读到这是不可能的。

尝试将日志记录在可以使用文件系统观察器监视的外部日志文件中

更新:再次找到它.. http://logging.apache.org/log4net/release/manual/configuration.html#.config%20Files

在运行时无法重新加载 app.config。

于 2008-11-07T13:46:35.033 回答
0

我建议使用另一个 XML 文件而不是 app.config。您甚至可以查看文件的更改并在更改时自动重新加载它。

于 2008-11-07T13:46:55.593 回答
0

实际上使用:

应用程序.restart();

对我来说效果很好。

问候

乔治

于 2009-07-29T07:55:04.573 回答
0

我尝试使用 RefreshSection 方法并使用以下代码示例使其工作:

class Program
    {
        static void Main(string[] args)
        {
            string value = string.Empty, key = "mySetting";
            Program program = new Program();

            program.GetValue(program, key);
            Console.WriteLine("--------------------------------------------------------------");
            Console.WriteLine("Press any key to exit...");
            Console.ReadLine();
        }

        /// <summary>
        /// Gets the value of the specified key from app.config file.
        /// </summary>
        /// <param name="program">The instance of the program.</param>
        /// <param name="key">The key.</param>
        private void GetValue(Program program, string key)
        {
            string value;
            if (ConfigurationManager.AppSettings.AllKeys.Contains(key))
            {
                Console.WriteLine("--------------------------------------------------------------");
                Console.WriteLine("Key found, evaluating value...");
                value = ConfigurationManager.AppSettings[key];
                Console.WriteLine("Value read from app.confg for Key = {0} is {1}", key, value);
                Console.WriteLine("--------------------------------------------------------------");

                //// Update the value
                program.UpdateAppSettings(key, "newValue");
                //// Re-read from config file
                value = ConfigurationManager.AppSettings[key];
                Console.WriteLine("New Value read from app.confg for Key = {0} is {1}", key, value);
            }
            else
            {
                Console.WriteLine("Specified key not found in app.config");
            }
        }

        /// <summary>
        /// Updates the app settings.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        public void UpdateAppSettings(string key, string value)
        {
            Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

            if (configuration.AppSettings.Settings.AllKeys.Contains(key))
            {
                configuration.AppSettings.Settings[key].Value = value;
            }

            configuration.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
        }
于 2012-07-11T05:15:43.987 回答