134 votes

Modifier le fichier app.config par défaut au moment de l'exécution

J'ai le problème suivant :
Nous avons une application qui charge des modules (add ons). Ces modules peuvent avoir besoin d'entrées dans l'app.config (par exemple, la configuration WCF). Comme les modules sont chargés dynamiquement, je ne veux pas avoir ces entrées dans le fichier app.config de mon application.
Ce que je voudrais faire est le suivant :

  • Créer un nouveau app.config en mémoire qui incorpore les sections config des modules
  • Dites à mon application d'utiliser cette nouvelle app.config.

Note : Je ne veux pas écraser l'app.config par défaut !

Il devrait fonctionner de manière transparente, de sorte que, par exemple ConfigurationManager.AppSettings utilise ce nouveau fichier.

Lors de mon évaluation de ce problème, j'ai trouvé la même solution que celle proposée ici : Recharger app.config avec nunit .
Malheureusement, cela ne semble rien faire, car j'obtiens toujours les données à partir de l'app.config normal.

J'ai utilisé ce code pour le tester :

Console.WriteLine(ConfigurationManager.AppSettings["SettingA"]);
Console.WriteLine(Settings.Default.Setting);

var combinedConfig = string.Format(CONFIG2, CONFIG);
var tempFileName = Path.GetTempFileName();
using (var writer = new StreamWriter(tempFileName))
{
    writer.Write(combinedConfig);
}

using(AppConfig.Change(tempFileName))
{
    Console.WriteLine(ConfigurationManager.AppSettings["SettingA"]);
    Console.WriteLine(Settings.Default.Setting);
}

Il imprime les mêmes valeurs deux fois, bien que combinedConfig contient d'autres valeurs que le app.config normal.

0 votes

Héberger les modules dans des AppDomain avec le fichier de configuration approprié n'est pas une option ?

0 votes

Pas vraiment, car cela entraînerait un grand nombre d'appels Cross-AppDomain, car l'application interagit assez fortement avec les modules.

0 votes

Que diriez-vous d'un redémarrage de l'application lorsqu'un nouveau module doit être chargé ?

2voto

Merveilleuse discussion, j'ai ajouté plus de commentaires à la méthode ResetConfigMechanism pour comprendre la magie derrière les déclarations/appels dans la méthode. J'ai également ajouté la vérification de l'existence du chemin d'accès au fichier

using System;//AppDomain
using System.Linq;//Where
using System.Configuration;//app.config
using System.Reflection;//BindingFlags
using System.Io;

/// <summary>
/// Use your own App.Config file instead of the default.
/// </summary>
/// <param name="NewAppConfigFullPathName"></param>
public static void ChangeAppConfig(string NewAppConfigFullPathName)
{
    if(File.Exists(NewAppConfigFullPathName)
    {
      AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", 
      NewAppConfigFullPathName);
      ResetConfigMechanism();
      return;
    }
}

/// <summary>
/// Remove cached values from ClientConfigPaths.
/// Call this after changing path to App.Config.
/// </summary>
private static void ResetConfigMechanism()
{
    BindingFlags Flags = BindingFlags.NonPublic | BindingFlags.Static;
      /* s_initState holds one of the four internal configuration state.
          0 - Not Started, 1 - Started, 2 - Usable, 3- Complete

         Setting to 0 indicates the configuration is not started, this will 
         hint the AppDomain to reaload the most recent config file set thru 
         .SetData call
         More [here][1]

      */
    typeof(ConfigurationManager)
        .GetField("s_initState", Flags)
        .SetValue(null, 0);

    /*s_configSystem holds the configuration section, this needs to be set 
        as null to enable reload*/
    typeof(ConfigurationManager)
        .GetField("s_configSystem", Flags)
        .SetValue(null, null);

      /*s_current holds the cached configuration file path, this needs to be 
         made null to fetch the latest file from the path provided 
        */
    typeof(ConfigurationManager)
        .Assembly.GetTypes()
        .Where(x => x.FullName == "System.Configuration.ClientConfigPaths")
        .First()
        .GetField("s_current", Flags)
        .SetValue(null, null);
    return;
}

1voto

Ron Points 1

Si votre fichier de configuration est juste écrit avec des clés/valeurs dans "appSettings", alors vous pouvez lire un autre fichier avec ce code :

System.Configuration.ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = configFilePath;

System.Configuration.Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
AppSettingsSection section = (AppSettingsSection)configuration.GetSection("appSettings");

Vous pouvez alors lire section.Settings comme une collection de KeyValueConfigurationElement.

1 votes

Comme je l'ai déjà dit, je veux faire ConfigurationManager.GetSection lire le nouveau fichier que j'ai créé. Votre solution ne fait pas ça.

0 votes

@Daniel : pourquoi ? Vous pouvez spécifier n'importe quel fichier dans "configFilePath". Vous avez donc juste besoin de connaître l'emplacement du fichier que vous venez de créer. Ai-je oublié quelque chose ? Ou vous avez vraiment besoin d'utiliser "ConfigurationManager.GetSection" et rien d'autre ?

1 votes

Oui, il y a quelque chose qui vous échappe : ConfigurationManager.GetSection utilise le app.config par défaut. Il ne se soucie pas du fichier de configuration que vous avez ouvert avec OpenMappedExeConfiguration .

0voto

anvarbek raupov Points 2555

Daniel, si possible, essayez d'utiliser d'autres mécanismes de configuration. Nous sommes passés par cette voie où nous avions différents fichiers de configuration statiques/dynamiques en fonction de l'environnement/du profil/du groupe et c'est devenu assez compliqué à la fin.

Vous pourriez essayer une sorte de service Web de profil où vous ne spécifiez qu'une seule URL de service Web à partir du client et, en fonction des détails du client (vous pourriez avoir des dérogations au niveau du groupe/de l'utilisateur), il charge toute la configuration dont il a besoin. Nous avons également utilisé MS Enterprise Library pour une partie du projet.

c'est-à-dire que vous ne déployez pas la configuration avec votre client et que vous pouvez la gérer séparément de vos clients.

3 votes

Merci pour votre réponse. Cependant, la raison principale est d'éviter l'envoi de fichiers de configuration. Les détails de la configuration des modules sont chargés à partir d'une base de données. Mais comme je veux donner aux développeurs de modules le confort du mécanisme de configuration par défaut de .NET, je veux incorporer ces configurations de modules dans un fichier de configuration au moment de l'exécution et en faire le fichier de configuration par défaut. La raison en est simple : Il existe un grand nombre de bibliothèques qui peuvent être configurées via app.config (par exemple WCF, EntLib, EF, ...). Si j'introduisais un autre mécanisme de configuration, la configuration serait (suite)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X