Équivalent à 'app.config' pour une bibliothèque (DLL)

149

Existe-t-il un équivalent à app.configpour les bibliothèques (DLL)? Sinon, quel est le moyen le plus simple de stocker les paramètres de configuration spécifiques à une bibliothèque? Veuillez noter que la bibliothèque peut être utilisée dans différentes applications.

Louis Rhys
la source

Réponses:

161

Vous pouvez avoir un fichier de configuration séparé, mais vous devrez le lire "manuellement", le ConfigurationManager.AppSettings["key"]ne lira que la configuration de l'assembly en cours d'exécution.

En supposant que vous utilisez Visual Studio comme IDE, vous pouvez cliquer avec le bouton droit sur le projet souhaité → Ajouter → Nouvel élément → Fichier de configuration de l'application

Cela ajoutera App.configau dossier du projet, mettez vos paramètres là-dedans sous la <appSettings>section. Si vous n'utilisez pas Visual Studio et n'ajoutez pas le fichier manuellement, assurez-vous de lui donner un tel nom: DllName.dll.config , sinon le code ci-dessous ne fonctionnera pas correctement.

Maintenant, pour lire à partir de ce fichier ont une telle fonction:

string GetAppSetting(Configuration config, string key)
{
    KeyValueConfigurationElement element = config.AppSettings.Settings[key];
    if (element != null)
    {
        string value = element.Value;
        if (!string.IsNullOrEmpty(value))
            return value;
    }
    return string.Empty;
}

Et pour l'utiliser:

Configuration config = null;
string exeConfigPath = this.GetType().Assembly.Location;
try
{
    config = ConfigurationManager.OpenExeConfiguration(exeConfigPath);
}
catch (Exception ex)
{
    //handle errror here.. means DLL has no sattelite configuration file.
}

if (config != null)
{
    string myValue = GetAppSetting(config, "myKey");
    ...
}

Vous devrez également ajouter une référence à l'espace de noms System.Configuration pour que la classe ConfigurationManager soit disponible.

Lors de la construction du projet, en plus de la DLL, vous aurez également un DllName.dll.configfichier, c'est le fichier que vous devez publier avec la DLL elle-même.

Ce qui précède est un exemple de code de base, pour ceux qui sont intéressés par un exemple à grande échelle, veuillez vous référer à cette autre réponse .

Shadow Wizard est une oreille pour vous
la source
1
@Rodney essayez de changer string exeConfigPath = this.GetType().Assembly.Location;pour quelque chose comme:string exeConfigPath = @"C:\MyFolder\DllFolder\ExeName.exe";
Shadow Wizard is Ear For You
1
Une idée comment faire cela si la dll est copiée dans un dossier inconnu par l'outil de test d'unité de réaffectation?
Autodidacte
11
Un conseil pour quiconque l'implémente: pour automatiser la génération de DllName.dll.config en référençant des applications, j'ai simplement renommé app.config en DllName.dll.config, et changé la propriété "Copier dans le répertoire de sortie" en "Copier toujours" . De plus, j'avais besoin de chaînes de connexion, qui peuvent être récupérées à l'aide de config.ConnectionStrings.ConnectionStrings [connStringName] .ConnectionString.
Jeff G
2
le nom du fichier app.cfg est très important pour lire les valeurs appcfg, le nom du fichier doit être "DLL_NAME.DLL.CONFIG"
SaddamBinSyed
2
Correction à mon dernier commentaire. Dans ma solution VS2017, en supprimant mes nouveaux fichiers App.config non fonctionnels de mes projets de test et de DLL et en les rajoutant simplement à mon projet de test, cela commence soudainement à fonctionner! Mon paramètre App.config est désormais automatiquement inclus dans DLL.configs. Quel soulagement!
Zeek2
30

Malheureusement, vous ne pouvez avoir qu'un seul fichier app.config par exécutable, donc si vous avez des DLL liées à votre application, elles ne peuvent pas avoir leurs propres fichiers app.config.

La solution est la suivante: vous n'avez pas besoin de placer le fichier App.config dans le projet de la bibliothèque de classes.
Vous placez le fichier App.config dans l'application qui fait référence à la DLL de votre bibliothèque de classes.

Par exemple, disons que nous avons une bibliothèque de classes nommée MyClasses.dll qui utilise le fichier app.config comme ceci:

string connect = 
ConfigurationSettings.AppSettings["MyClasses.ConnectionString"];

Maintenant, disons que nous avons une application Windows nommée MyApp.exe qui fait référence à MyClasses.dll. Il contiendrait un App.config avec une entrée telle que:

<appSettings>
    <add key="MyClasses.ConnectionString"
         value="Connection string body goes here" />
</appSettings>

OU

Un fichier xml est le meilleur équivalent pour app.config. Utilisez xml sérialiser / désérialiser si nécessaire. Vous pouvez l'appeler comme vous le souhaitez. Si votre configuration est "statique" et n'a pas besoin d'être modifiée, vous pouvez également l'ajouter au projet en tant que ressource intégrée.

J'espère que ça donne une idée

PawanS
la source
6
ConfigurationSettingsest maintenant obsolète et remplacé par ConfigurationManager, donc l'équivalent serait maintenantConfigurationManager.AppSettings
Gone Coding
2
vote vers le bas. la question est par dll et non par application. meilleure solution: stackoverflow.com/a/5191101/2935383
raiserle
3
Je soupçonne que cette suggestion ne fonctionnera pas dans le cas des DLL à liaison tardive qui n'auraient aucune connaissance de l'exécutable qui les appelle.
beanmf
9

Les fichiers de configuration sont axés sur l'application et non sur l'assembly. Vous devrez donc mettre les sections de configuration de votre bibliothèque dans le fichier de configuration de chaque application qui utilise votre bibliothèque.

Cela dit, il n'est pas recommandé d'obtenir la configuration à partir du fichier de configuration de l'application, en particulier le appSettings section, dans une bibliothèque de classes. Si votre bibliothèque a besoin de paramètres, ils devraient probablement être passés comme arguments de méthode dans les constructeurs, les méthodes de fabrique, etc. par celui qui appelle votre bibliothèque. Cela empêche les applications appelantes de réutiliser accidentellement les entrées de configuration attendues par la bibliothèque de classes.

Cela dit, les fichiers de configuration XML sont extrêmement pratiques, donc le meilleur compromis que j'ai trouvé consiste à utiliser des sections de configuration personnalisées. Vous obtenez de mettre la configuration de votre bibliothèque dans un fichier XML qui est automatiquement lu et analysé par le framework et vous évitez les accidents potentiels.

Vous pouvez en savoir plus sur les sections de configuration personnalisées sur MSDN et Phil Haack a également un bel article à leur sujet.

madd0
la source
7
"ce n'est pas une bonne pratique d'obtenir la configuration à partir d'un fichier de configuration dans une bibliothèque de classes" - Je ne suis pas du tout d'accord avec cela. Par exemple, une bibliothèque de classes DAL doit normalement obtenir des données de configuration telles que des chaînes de connexion à partir du fichier de configuration d'application plutôt que de transmettre ces informations à partir du niveau BLL. Toutes les classes Framework qui utilisent la configuration (par exemple l'appartenance à ASP.NET) fonctionnent de cette manière.
Joe
J'ai légèrement modifié ma réponse. Je maintiens toujours ce que j'ai dit, mais vous avez raison, je n'ai jamais eu l'intention de laisser entendre que les fichiers de configuration ne devraient pas du tout être utilisés. Ce que je voulais dire, c'est que, au lieu des conventions basées appSettingssur des conventions , les sections personnalisées offrent une excellente alternative; c'est à peu près ce que l'appartenance à ASP.NET utilise après tout.
madd0
5
public class ConfigMan
{
    #region Members

    string _assemblyLocation;
    Configuration _configuration;

    #endregion Members

    #region Constructors

    /// <summary>
    /// Loads config file settings for libraries that use assembly.dll.config files
    /// </summary>
    /// <param name="assemblyLocation">The full path or UNC location of the loaded file that contains the manifest.</param>
    public ConfigMan(string assemblyLocation)
    {
        _assemblyLocation = assemblyLocation;
    }

    #endregion Constructors

    #region Properties

    Configuration Configuration
    {
        get
        {
            if (_configuration == null)
            {
                try
                {
                    _configuration = ConfigurationManager.OpenExeConfiguration(_assemblyLocation);
                }
                catch (Exception exception)
                {
                }
            }
            return _configuration;
        }
    }

    #endregion Properties

    #region Methods

    public string GetAppSetting(string key)
    {
        string result = string.Empty;
        if (Configuration != null)
        {
            KeyValueConfigurationElement keyValueConfigurationElement = Configuration.AppSettings.Settings[key];
            if (keyValueConfigurationElement != null)
            {
                string value = keyValueConfigurationElement.Value;
                if (!string.IsNullOrEmpty(value)) result = value;
            }
        }
        return result;
    }

    #endregion Methods
}

Juste pour quelque chose à faire, j'ai refactoré la première réponse dans une classe. L'utilisation est quelque chose comme:

ConfigMan configMan = new ConfigMan(this.GetType().Assembly.Location);
var setting = configMan.GetAppSetting("AppSettingsKey");
Firegarden
la source
4

Si vous ajoutez des paramètres à un projet de bibliothèque de classes dans Visual Studio (propriétés du projet, paramètres), il ajoutera un fichier app.config à votre projet avec les sections userSettings / applicatioNSettings pertinentes et les valeurs par défaut de ces paramètres à partir de vos paramètres. fichier.

Cependant, ce fichier de configuration ne sera pas utilisé lors de l'exécution - à la place, la bibliothèque de classes utilise le fichier de configuration de son application d'hébergement.

Je pense que la principale raison de la génération de ce fichier est que vous puissiez copier / coller les paramètres dans le fichier de configuration de l'application hôte.

Joe
la source
4

Je crée actuellement des plugins pour une marque de logiciels de vente au détail, qui sont en fait des bibliothèques de classes .net. En tant que condition, chaque plugin doit être configuré à l'aide d'un fichier de configuration. Après quelques recherches et tests, j'ai compilé la classe suivante. Il fait parfaitement le travail. Notez que je n'ai pas implémenté la gestion des exceptions locales dans mon cas car j'attrape les exceptions à un niveau supérieur.

Quelques ajustements peuvent être nécessaires pour obtenir le bon point décimal, en cas de décimales et de doubles, mais cela fonctionne bien pour mon CultureInfo ...

static class Settings
{
    static UriBuilder uri = new UriBuilder(Assembly.GetExecutingAssembly().CodeBase);
    static Configuration myDllConfig = ConfigurationManager.OpenExeConfiguration(uri.Path);
    static AppSettingsSection AppSettings = (AppSettingsSection)myDllConfig.GetSection("appSettings");
    static NumberFormatInfo nfi = new NumberFormatInfo() 
    { 
        NumberGroupSeparator = "", 
        CurrencyDecimalSeparator = "." 
    };

    public static T Setting<T>(string name)
    {
        return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);
    }
}

Exemple de fichier App.Config

<add key="Enabled" value="true" />
<add key="ExportPath" value="c:\" />
<add key="Seconds" value="25" />
<add key="Ratio" value="0.14" />

Usage:

  somebooleanvar = Settings.Setting<bool>("Enabled");
  somestringlvar = Settings.Setting<string>("ExportPath");
  someintvar =     Settings.Setting<int>("Seconds");
  somedoublevar =  Settings.Setting<double>("Ratio");

Crédits à Shadow Wizard et MattC

Yiannis Leoussis
la source
1
Cela devrait être la réponse acceptée. Très compact et "fonctionne dès la sortie de la boîte". Good stuff
nmarler
2

En réponse à la question d'origine, j'ajoute généralement le fichier de configuration dans mon projet de test en tant que lien; vous pouvez ensuite utiliser l'attribut DeploymentItem pour l'ajouter au dossier Out du test.

[TestClass]
[DeploymentItem("MyProject.Cache.dll.config")]
public class CacheTest
{
    .
    .
    .
    .
}

En réponse aux commentaires selon lesquels les assemblys ne peuvent pas être spécifiques à un projet, ils le peuvent et cela offre une grande flexibilité, notamment. lorsque vous travaillez avec des cadres IOC.

Allan Elder
la source
2

J'ai rencontré le même problème et je l'ai résolu en créant une classe statique Parametersaprès avoir ajouté un fichier de configuration d'application au projet:

public static class Parameters
{
    // For a Web Application
    public static string PathConfig { get; private set; } =
        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "web.config");

    // For a Class Library
    public static string PathConfig { get; private set; } =
        Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin", "LibraryName.dll.config");

    public static string GetParameter(string paramName)
    {
        string paramValue = string.Empty;

        using (Stream stream = File.OpenRead(PathConfig))
        {
            XDocument xdoc = XDocument.Load(stream);

            XElement element = xdoc.Element("configuration").Element("appSettings").Elements().First(a => a.Attribute("key").Value == paramName);
            paramValue = element.Attribute("value").Value;
        }

        return paramValue;
    }
}

Ensuite, obtenez un paramètre comme celui-ci:

Parameters.GetParameter("keyName");
krlzlx
la source
1
Brillant! Cela m'a aidé à exécuter les tests automatisés de mon pilote d'application Windows sur les machines cibles. Les dll dans mon cas provenaient d'un projet de test. La seule chose que j'ajouterais est que dans Win App Driver (et peut-être dans d'autres formes de tests automatisés), BaseDirectory est en fait le dossier de sortie qui change à chaque fois. J'ai dû sous-chaîne comme celle-ci ... AppDomain.CurrentDomain.BaseDirectory.Substring (0, AppDomain.CurrentDomain.BaseDirectory.IndexOf ("TestResults")). de cette façon, je pourrais couper le dossier de sortie indésirable car mon fichier de configuration était dans le même dossier que mes dll de test.
Ewan
1

les assemblys n'ont pas leur propre fichier app.config. Ils utilisent le fichier app.config de l'application qui les utilise. Donc, si votre assemblage attend certaines choses dans le fichier de configuration, assurez-vous simplement que le fichier de configuration de votre application contient ces entrées.

Si votre assembly est utilisé par plusieurs applications, chacune de ces applications devra avoir ces entrées dans leur fichier app.config.

Ce que je vous recommande de faire, c'est de définir des propriétés sur les classes de votre assembly pour ces valeurs par exemple

private string ExternalServicesUrl
{
  get
  {
    string externalServiceUrl = ConfigurationManager.AppSettings["ExternalServicesUrl"];
    if (String.IsNullOrEmpty(externalServiceUrl))
      throw new MissingConfigFileAppSettings("The Config file is missing the appSettings entry for: ExternalServicesUrl");
    return externalServiceUrl;
  }
}

Ici, la propriété ExternalServicesUrl obtient sa valeur à partir du fichier de configuration de l'application. Si une application utilisant cet assembly manque ce paramètre dans le fichier de configuration, vous obtiendrez une exception o il est clair que quelque chose a disparu.

MissingConfigFileAppSettings est une exception personnalisée. Vous souhaiterez peut-être lever une exception différente.

Bien sûr, une meilleure conception serait que la méthode de ces classes reçoive ces valeurs en tant que paramètres plutôt que de s'appuyer sur la configuration du fichier de configuration. De cette façon, les applications utilisant ces classes peuvent décider d'où et comment elles fournissent ces valeurs.

Shiv Kumar
la source
Attention à ce qui précède: lors de l'exécution de tests xUnit sur votre DLL d'assemblage .NET, xUnit lira le .config de la bibliothèque, au moment de l'exécution. Et il ignorera tout App.config ajouté au projet de test ou DLL.
Zeek2
1

Utilisez ajouter un élément existant, sélectionnez la configuration de l'application à partir du projet dll. Avant de cliquer sur Ajouter, utilisez la petite flèche vers le bas sur le côté droit du bouton Ajouter pour "ajouter en tant que lien"

Je fais ça tout le temps dans mon dev.

fantômeJago
la source
1

Préambule : j'utilise NET 2.0;

La solution publiée par Yiannis Leoussis est acceptable mais j'ai eu un problème avec elle.

Tout d'abord, le static AppSettingsSection AppSettings = (AppSettingsSection)myDllConfig.GetSection("appSettings");retourne null. J'ai dû le changer enstatic AppSettingSection = myDllConfig.AppSettings;

Alors le return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);n'a pas de piège pour les exceptions. Alors je l'ai changé

try
{
    return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);
}
catch (Exception ex)
{
    return default(T);
}

Cela fonctionne très bien mais si vous avez une dll différente, vous devez réécrire à chaque fois le code de chaque assembly. Donc, ceci est ma version pour une classe à instancier à chaque fois que vous en avez besoin.

public class Settings
{
    private AppSettingsSection _appSettings;
    private NumberFormatInfo _nfi;

    public Settings(Assembly currentAssembly)
    {
        UriBuilder uri = new UriBuilder(currentAssembly.CodeBase);
        string configPath = Uri.UnescapeDataString(uri.Path);
        Configuration myDllConfig = ConfigurationManager.OpenExeConfiguration(configPath);
        _appSettings = myDllConfig.AppSettings;
        _nfi = new NumberFormatInfo() 
        { 
            NumberGroupSeparator = "", 
            CurrencyDecimalSeparator = "." 
        };
    }


    public T Setting<T>(string name)
    {
        try
        {
            return (T)Convert.ChangeType(_appSettings.Settings[name].Value, typeof(T), _nfi);
        }
        catch (Exception ex)
        {
            return default(T);
        }
    }
}

Pour une config:

<add key="Enabled" value="true" />
<add key="ExportPath" value="c:\" />
<add key="Seconds" value="25" />
<add key="Ratio" value="0.14" />

Utilisez-le comme:

Settings _setting = new Settings(Assembly.GetExecutingAssembly());

somebooleanvar = _settings.Setting<bool>("Enabled");
somestringlvar = _settings.Setting<string>("ExportPath");
someintvar =     _settings.Setting<int>("Seconds");
somedoublevar =  _settings.Setting<double>("Ratio");
Matteo Gaggiano
la source
Veuillez vérifier le vote de suppression. Mon erreur a été d'envoyer la réponse en l'écrivant.
Matteo Gaggiano
0

Autant que je sache, vous devez copier + coller les sections que vous voulez de la bibliothèque .config dans le fichier .config des applications. Vous n'obtenez qu'un seul app.config par instance d'exécutable.

Mike
la source
si vous utilisez des sections de configuration personnalisées, vous pouvez utiliser l'attribut configSource: <MySection configSource = "mysection.config" /> et le fichier de configuration ne copie qu'avec dll
Jan Remunda
J'ai ajouté de nouvelles questions comme demandé, par exemple sur la fonction renvoyant toujours une chaîne vide et les paramètres du serveur de messagerie> stackoverflow.com/questions/25123544/... et> stackoverflow.com/questions/25138788/… donc j'espère que quelqu'un y répondra comme je suis presque sur le point de coder en dur les valeurs dans la DLL!
MonkeyMagix
0

Pourquoi ne pas utiliser:

  • [ProjectNamespace].Properties.Settings.Default.[KeyProperty] pour C #
  • My.Settings.[KeyProperty] pour VB.NET

Il vous suffit de mettre à jour visuellement ces propriétés au moment de la conception via:

[Solution Project]->Properties->Settings

Pedro Mora
la source
Cela créera automatiquement un fichier de configuration pour la dll. Mais vous ne pouvez pas lire les valeurs modifiées du fichier de configuration au moment de l'exécution. Enfin, il affichera les valeurs de votre application appelante. Voir aussi @Joe answer
Code Pope
Non s'il est configuré pour la configuration de l'utilisateur. L'idée est de modifier les besoins de l'utilisateur, de les configurer au moment de l'exécution, puis de les enregistrer. Ensuite, lorsque l'utilisateur travaille avec la bibliothèque, il charge sa configuration, sauvegardée dans son chemin utilisateur respectif, mais ne fonctionne que pour lui.
Pedro Mora
0

l'utilisation à partir de configurations doit être très très simple comme ceci:

var config = new MiniConfig("setting.conf");

config.AddOrUpdate("port", "1580");

if (config.TryGet("port", out int port)) // if config exist
{
    Console.Write(port);
}

pour plus de détails, voir MiniConfig

Rahmat Anjirabi
la source