.net dinamicamente atualização app.config
-
07-07-2019 - |
Pergunta
Como posso recarregar dinamicamente o app.config em um aplicativo .NET do Windows? Eu preciso para transformar o log on e off de forma dinâmica e não apenas com base no valor no início da aplicação.
ConfigurationManager.RefreshSection ( "appSettings") não funciona e eu também tentei abrir explicitamente o arquivo de configuração usando OpenExeConfiguration mas eu sempre obter o valor em cache na inicialização do aplicativo e não o valor atual.
Eu aceitei a resposta de criar uma seção de configuração personalizada. Como uma nota de lado e erro tolo - se você estiver executando a partir do IDE não há nenhum ponto em atualizar o arquivo app.config e esperando mudanças. Yuo tem que modificar o arquivo exe.config na pasta bin \ debug. Doh!
Solução
Você pode atualizar seu próprio seção a maneira de dizer:
ConfigurationManager.RefreshSection("yoursection/subsection");
Apenas mover um registro de verdadeiro / falso em uma seção e você vai ficar bem.
Outras dicas
Se você estiver usando log4net, você pode fazer o que você pediu:
Embora seja possível adicionar as definições de configuração log4net para app.config
do seu projeto ou arquivo web.config
, é preferível colocá-los em um arquivo de configuração separado. Além da vantagem óbvia de manutenção, tem a vantagem adicional de que log4net pode colocar um objeto FileSystemWatcher
em seu arquivo de configuração para monitorar quando ele muda e atualizar suas configurações de forma dinâmica.
Para usar um arquivo de configuração separado, adicionar um arquivo chamado Log4Net.config ao seu projeto e adicione o seguinte atributo para o arquivo AssemblyInfo.cs:
[assembly: log4net.Config.XmlConfigurator(ConfigFile="Log4Net.config", Watch = true)]
Nota: para aplicações web, isso pressupõe reside Log4Net.config
na raiz web. Verifique se o arquivo log4net.config
é marcado como “Copiar para a saída.” -> “Copiar Sempre” em Propriedades
A seguir é o hack que você pode colocar isso vai fazer config para ler do disco.
Você só precisa salvar o arquivo de configuração no modo modificado e, em seguida, atualize esta irá fazer a aplicação para ler a agian arquivo do disco.
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");
Apenas uma nota, em WinForms, você pode fazer alterações programáticas para o seu app antes de seu aplicativo carrega (antes Application.Start(new Form1())
), contanto que você usar System.Xml
vez de 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);
Eu escrevi essa implementação para alterar o nível de log em tempo de execução e persistir o novo limiar de volta para o app.config (na verdade, o Application.exe.config).
A interface:
internal interface ILoggingConfiguration
{
void SetLogLevel(string level);
string GetLogLevel();
}
A implementação:
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
}
Os Log4NetUtils classe helper:
public sealed class Log4NetUtils
{
private static readonly ILoggerRepository _loggerRepository =
LoggerManager.GetAllRepositories().First();
public static Level ConvertToLevel(string level)
{
return _loggerRepository.LevelMap[level];
}
}
O código 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>
Eu não acho que há alguma maneira de fazer isso, a menos que você escrever seu próprio leitor de arquivo de configuração usando XML. Porque não basta virar o registo ligado ou desligado no início da sua aplicação com base na configuração arquivo de configuração, e em seguida, basta ligá-lo ou desligado de forma dinâmica enquanto o programa está sendo executado?
Eu acho que eu li na documentação log4net que isso não é possível.
Tente ter o registro em um arquivo de log externo que pode ser visto com um FileSystemWatcher
Update: Encontrado lo novamente .. http://logging.apache.org/log4net/release /manual/configuration.html#.config%20Files
Não há nenhuma maneira de recarregar o app.config durante a execução.
Eu recomendaria usar outro arquivo XML e não app.config. Você pode até mesmo assistir o arquivo de mudanças e automaticamente recarregá-lo quando ele muda.
Na verdade usando um:
Application.restart ();
tem funcionado muito bem para mim.
Saudações
Jorge
Eu tentei usar o método RefreshSection e tenho que trabalhar usando o seguinte exemplo de código:
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");
}