web-dev-qa-db-fra.com

C # DLL fichier de configuration

J'essaie d'ajouter un fichier app.config à ma DLL, mais toutes les tentatives ont échoué. 

Selon MusicGenesis dans ' Placer les informations de configuration dans un DLL ', cela ne devrait pas poser de problème. Alors évidemment, je fais quelque chose de mal ...

Le code suivant doit renvoyer ma ConnectionString à partir de ma DLL:

return ConfigurationManager.AppSettings["ConnectionString"];

Cependant, lorsque je copie le fichier app.config dans mon application console, cela fonctionne correctement.

Des idées?

179
MegaByte

Créer un fichier de configuration .NET pour un fichier .DLL n’est pas chose aisée. Le mécanisme de configuration .NET intègre de nombreuses fonctionnalités facilitant la mise à niveau/la mise à jour de l'application et protégeant les applications installées contre le piétinement des fichiers de configuration.

Il existe une grande différence entre la manière dont une DLL est utilisée et la manière dont une application est utilisée. Il est peu probable que plusieurs copies d'une application soient installées sur le même ordinateur pour le même utilisateur. Mais vous pouvez très bien avoir 100 applications ou bibliothèques différentes utilisant toutes des DLL .NET.

Alors qu'il est rarement nécessaire de suivre les paramètres séparément pour différentes copies d'une application dans un même profil utilisateur, il est très peu probable que vous souhaitiez utiliser toutes les différentes utilisations d'un DLL partager la configuration les uns avec les autres. Pour cette raison, lorsque vous récupérez un objet de configuration à l'aide de la méthode "normale", l'objet que vous récupérez est lié à la configuration du domaine d'application dans lequel vous vous exécutez, plutôt qu'à l'assembly particulier.

Le domaine d'application est lié à l'assembly racine qui a chargé l'assembly dans lequel se trouve votre code. Dans la plupart des cas, il s'agira de l'assembly de votre fichier principal .exe, qui est ce qui a chargé le fichier .dll. Il est possible de faire tourner d'autres domaines d'application au sein d'une application, mais vous devez explicitement fournir des informations sur ce qu'est l'assembly racine de ce domaine d'application.

Pour toutes ces raisons, la procédure de création d'un fichier de configuration spécifique à la bibliothèque n'est pas très pratique. C’est le même processus que vous utiliseriez pour créer un fichier de configuration portable arbitraire, non lié à un assemblage particulier, mais pour lequel vous souhaitez utiliser le schéma XML, la section de configuration et les mécanismes d’éléments de configuration de .NET, etc. Ceci implique la création d'un ExeConfigurationFileMap objet, il charge les données pour identifier l'emplacement du fichier de configuration, puis appelle ConfigurationManager.OpenMappedExeConfiguration pour l'ouvrir dans une nouvelle instance Configuration. Ceci va vous couper de la protection de version offerte par le mécanisme de génération automatique de chemins.

Statistiquement, vous utilisez probablement cette bibliothèque dans un environnement interne et il est peu probable que plusieurs applications l'utilisent au sein d'un ordinateur/utilisateur. Mais sinon, il y a quelque chose que vous devriez garder à l'esprit. Si vous utilisez un seul fichier de configuration global pour votre DLL, quelle que soit l'application qui le référence, vous devez vous inquiéter des conflits d'accès. Si deux applications référençant votre bibliothèque s'exécutent en même temps, chacune avec son propre objet Configuration ouvert, une sauvegarde des modifications provoquera une exception lors de la prochaine tentative d'extraction ou de sauvegarde des données dans l'autre. app.

Le moyen le plus sûr et le plus simple de contourner ce problème consiste à exiger que l’Assemblée qui charge votre DLL fournisse également des informations sur elle-même, ou à la détecter en examinant le domaine App de l’Assemblée référent. Utilisez cette option pour créer une sorte de structure de dossiers permettant de conserver des fichiers de configuration utilisateur distincts pour chaque application faisant référence à votre DLL.

Si vous êtes certain vous voulez avoir des paramètres globaux pour votre DLL peu importe où il est référencé, vous devrez déterminer votre emplacement plutôt que .NET déterminer un approprié automatiquement. Vous devrez également vous montrer agressif dans la gestion de l'accès au fichier. Vous aurez besoin de mettre en cache autant que possible, en conservant l'instance Configuration UNIQUEMENT aussi longtemps qu'il faudra pour charger ou enregistrer, ouvrir immédiatement avant et disposer immédiatement après. Enfin, vous aurez besoin d’un mécanisme de verrouillage pour protéger le fichier lors de sa modification par l’une des applications utilisant la bibliothèque.

272
Chris Ammerman

si vous souhaitez lire les paramètres du fichier de configuration de la DLL mais pas des applications racine web.config ou app.config, utilisez le code ci-dessous pour lire la configuration dans la dll.

var appConfig = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
string dllConfigData = appConfig.AppSettings.Settings["dllConfigData"].Value;
96
Morbia

J'ai eu le même problème et j'ai cherché sur le Web pendant plusieurs heures, mais comme je ne trouvais pas de solution, j'ai créé le mien. Je me demandais pourquoi le système de configuration .net est si inflexible.

Fond: Je veux que mon DAL.dll ait son propre fichier de configuration pour la base de données et les paramètres DAL. J'ai également besoin de app.config pour Enterprise Library et de ses propres configurations. J'ai donc besoin à la fois de app.config et de dll.config.

Ce que je ne voulais pas, c’est de faire passer chaque propriété/paramètre de l’application à ma couche DAL!

plier le "AppDomain.CurrentDomain.SetupInformation.ConfigurationFile" n'est pas possible car j'en ai besoin pour le comportement normal de app.config.

Mes exigences/points de vue étaient:

  • AUCUNE copie manuelle de quoi que ce soit de ClassLibrary1.dll.config vers WindowsFormsApplication1.exe.config, car cela n’est pas reproductible pour les autres développeurs.
  • conserve l'utilisation de la frappe forte "Properties.Settings.Default.NameOfValue" (comportement des paramètres) car je pense que c'est une fonctionnalité majeure et que je ne voulais pas la perdre
  • J'ai découvert le manque d'ApplicationSettingsBase pour injecter votre propre fichier de configuration/gestion ou votre propre gestion (tous les champs nécessaires sont privés dans ces classes)
  • l'utilisation de la redirection de fichier "configSource" n'est pas possible car nous devrions copier/réécrire le fichier ClassLibrary1.dll.config et fournir plusieurs fichiers XML pour plusieurs sections (je n'aimais pas cela non plus)
  • Je n'aimais pas écrire mon propre SettingsProvider pour cette tâche simple, comme le suggère MSDN, car je pensais que ce serait tout simplement trop.
  • Je n'ai besoin que des sections applicationSettings et connectionStrings du fichier de configuration

Je suis venu avec la modification du fichier Settings.cs et mis en œuvre une méthode qui ouvre le ClassLibrary1.dll.config et lit les informations de la section dans un champ privé. Après cela, j'ai remplacé "this [string propertyName]" afin que le fichier Settings.Desginer.cs généré soit appelé dans ma nouvelle propriété au lieu de la classe de base. Là, le réglage est lu hors de la liste. 

Enfin, il y a le code suivant:

internal sealed partial class Settings
{
    private List<ConfigurationElement> list;

    /// <summary>
    /// Initializes a new instance of the <see cref="Settings"/> class.
    /// </summary>
    public Settings()
    {
        this.OpenAndStoreConfiguration();
    }

    /// <summary>
    /// Opens the dll.config file and reads its sections into a private List of ConfigurationElement.
    /// </summary>
    private void OpenAndStoreConfiguration()
    {
        string codebase = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
        Uri p = new Uri(codebase);
        string localPath = p.LocalPath;
        string executingFilename = System.IO.Path.GetFileNameWithoutExtension(localPath);
        string sectionGroupName = "applicationSettings";
        string sectionName = executingFilename + ".Properties.Settings";
        string configName = localPath + ".config";
        ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
        fileMap.ExeConfigFilename = configName;
        Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);

        // read section of properties
        var sectionGroup = config.GetSectionGroup(sectionGroupName);
        var settingsSection = (ClientSettingsSection)sectionGroup.Sections[sectionName];
        list = settingsSection.Settings.OfType<ConfigurationElement>().ToList();

        // read section of Connectionstrings
        var sections = config.Sections.OfType<ConfigurationSection>();
        var connSection = (from section in sections
                           where section.GetType() == typeof(ConnectionStringsSection)
                           select section).FirstOrDefault() as ConnectionStringsSection;
        if (connSection != null)
        {
            list.AddRange(connSection.ConnectionStrings.Cast<ConfigurationElement>());
        }
    }

    /// <summary>
    /// Gets or sets the <see cref="System.Object"/> with the specified property name.
    /// </summary>
    /// <value></value>
    public override object this[string propertyName]
    {
        get
        {
            var result = (from item in list
                         where Convert.ToString(item.ElementInformation.Properties["name"].Value) == propertyName
                         select item).FirstOrDefault();
            if (result != null)
            {
                if (result.ElementInformation.Type == typeof(ConnectionStringSettings))
                {
                    return result.ElementInformation.Properties["connectionString"].Value;
                }
                else if (result.ElementInformation.Type == typeof(SettingElement))
                {
                    return result.ElementInformation.Properties["value"].Value;
                }
            }
            return null;
        }
        // ignore
        set
        {
            base[propertyName] = value;
        }
    }

Vous devrez simplement copier votre ClassLibrary1.dll.config du répertoire de sortie ClassLibrary1 vers le répertoire de sortie de votre application . Peut-être que quelqu'un le trouvera utile. 

19
Sven

Lors de l'utilisation de ConfigurationManager, je suis presque sûr qu'il charge le fichier de configuration process/AppDomain (app.config/web.config). Si vous voulez charger un fichier de configuration spécifique, vous devrez demander spécifiquement ce fichier par son nom ...

Tu pourrais essayer:

var config = ConfigurationManager.OpenExeConfiguration("foo.dll");
config.ConnectionStrings. [etc]
14
Marc Gravell

ConfigurationManager.AppSettings renvoie les paramètres définis pour l'application. Vous ne pouvez pas y accéder, mais les paramètres de l'application qui seront retournés.

Si vous utilisez votre dll depuis une autre application, ConnectionString doit être dans les app.settings de l'application.

13
Jorge Córdoba

Je sais que la soirée est tardive, mais je pensais partager la solution que j'utilise pour les DLL.

Je suis plus du K.I.S.S. école de pensée, donc quand j’ai un .NET DLL qui veut stocker des points de données externes qui contrôlent son fonctionnement ou son déroulement, etc., je crée simplement une classe "config" qui n’a que des propriétés publiques qui stockent tous les points de données dont il a besoin et que je voudrais pouvoir contrôler de manière externe à la DLL afin d’empêcher sa recompilation de procéder aux modifications. Ensuite, j'utilise la sérialisation XML de .Net pour enregistrer et charger la représentation d'objet de la classe dans un fichier.

Il existe alors de nombreuses manières de gérer sa lecture et son accès, depuis un singleton, une classe d’utilitaire statique, vers des méthodes d’extension, etc. Cela dépend de la structure de votre DLL et de la méthode adaptée à votre DLL meilleur.

5
Rodney S. Foley

vous avez raison, vous pouvez lire le fichier de configuration d’une dll. J'ai eu du mal avec cela pendant un jour jusqu'à ce que j'ai découvert que le fichier de configuration était le problème. Voir mon code ci-dessous. il a pu courir.

        ExeConfigurationFileMap map = new ExeConfigurationFileMap();
        map.ExeConfigFilename = Assembly.GetExecutingAssembly().Location + ".config";
        Configuration libConfig = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
        AppSettingsSection section = (libConfig.GetSection("appSettings") as AppSettingsSection);
        Console.WriteLine(section.Settings["dnd_shortcodes"].Value);

mon Plugin1.dll.config était comme ci-dessous;

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <appSettings>
  <add key="cmd_location" value="http://..."/>
  <add key="dnd_shortcodes" value="142,145,146,157,165,167,168,171,173,176,178,404,40"/>
 </appSettings>
</configuration>

J'ai découvert que la balise <appSettings> ne figurait pas dans mon fichier de configuration. Regardez autour de vous, votre problème aurait pu être différent, mais pas si éloigné du mien.

3
mugume david

Puisque l’Assembly réside dans un cache temporaire, vous devez combiner le chemin pour obtenir la configuration de la DLL:

var appConfig = ConfigurationManager.OpenExeConfiguration(
    Path.Combine(Environment.CurrentDirectory, Assembly.GetExecutingAssembly().ManifestModule.Name));
3
Lin Song Yang

On dirait que ces fichiers de configuration sont vraiment déroutants à clarifier, car leur comportement change de l'environnement de développement au déploiement. Apparemment, une DLL peut avoir son propre fichier de configuration, mais une fois que vous avez copié et collé la dll (avec son fichier de configuration) ailleurs, le tout a cessé de fonctionner. La seule solution consiste à fusionner manuellement les fichiers app.config en un seul fichier, qui ne sera utilisé que par l'exécutable. Par exemple myapp.exe aura un fichier myapp.exe.config qui contient tous les paramètres de toutes les dll utilisées par myapp.exe . J'utilise VS 2008. 

3
kenny

Si vous utilisez des bibliothèques qui recherchent une grande quantité de configuration en arrière-plan, telle que WCF, vous pouvez envisager de procéder de la manière suivante:

AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "MyWcfClientWrapper.dll.config");

Ou dans PowerShell:

[AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", "MyWcfClientWrapper.dll.config")

OMI cette technique est une odeur de code et ne convient vraiment que pour une utilisation dans les scripts ad hoc. Si vous souhaitez le faire dans le code de production, le moment est peut-être venu de procéder à une révision de l'architecture.

Ce qui suit n'est PAS recommandé:
Comme curiosité technique, voici une variation sur le thème. Vous pouvez créer un constructeur statique dans l'une des classes hébergées dans la DLL et effectuer cet appel à partir de là. Je ne recommanderais pas cela sauf en dernier recours. 

3
Paul Williams

J'ai trouvé ce qui semble être une bonne solution à ce problème. J'utilise VS 2008 C #. Ma solution implique l'utilisation d'espaces de noms distincts entre plusieurs fichiers de configuration. J'ai posté la solution sur mon blog: http://tommiecarter.blogspot.com/2011/02/how-to-access-multiple-config-files-in.html .

Par exemple:

Cet espace de noms lit/écrit les paramètres dll:

var x = company.dlllibrary.Properties.Settings.Default.SettingName;
company.dlllibrary.Properties.Settings.Default.SettingName = value;

Cet espace de noms lit/écrit les paramètres exe:

company.exeservice.Properties.Settings.Default.SettingName = value;
var x = company.exeservice.Properties.Settings.Default.SettingName;

Certaines mises en garde sont mentionnées dans l'article. HTH

2
Tommie C.

La solution complète ne se trouve pas souvent au même endroit ... 

1) Créez un fichier de configuration d'application et nommez-le "yourDllName.dll.config".
2) Faites un clic droit sur le fichier de configuration créé ci-dessus dans VS Solution Explorer, cliquez sur propriétés.
--- set "Build Action" = Contenu
--- set "Copier dans le répertoire de sortie" = Toujours
3) Ajoutez une section appSettings au fichier de configuration (votreDllName.dll.config) avec votre yourKeyName et votreKeyValue.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="yourKeyName" value="yourKeyValue"/>
  </appSettings>
</configuration>

4) Ajoutez System.Configuration à vos références de dll/classe/projet
5) Ajoutez les instructions using à votre code lorsque vous souhaitez accéder au paramètre de configuration

using System.Configuration;
using System.Reflection;

6) Accéder à la valeur 

string keyValue = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettings.Settings["yourKeyName"].Value;

7) réjouissez-vous, cela fonctionne

IMHO, cela ne devrait être utilisé que lors du développement d'une nouvelle dll/bibliothèque. 

#if (DEBUG && !FINALTESTING)
   string keyValue = ConfigurationManager.OpenExeConfiguration...(see 6 above)
#else
   string keyValue = ConfigurationManager.AppSettings["yourKeyName"];
#endif

Le fichier de configuration finit par être une excellente référence, car vous ajoutez les appSettings de la DLL à votre application réelle. 

1
David C Fuchs

Comme le dit Marc, cela n’est pas possible (même si Visual Studio vous permet d’ajouter un fichier de configuration d’application dans un projet de bibliothèque de classes).

Vous voudrez peut-être consulter la classe AssemblySettings qui semble rendre les fichiers de configuration d'Assembly possibles.

1
Gerrie Schenck

Dans ce post, un problème similaire a été discuté et résoudre mon problème Comment charger un fichier de paramètres d'application distinct et le fusionner avec les paramètres actuels? pourrait être utile

0
dhailis

Pour une dll, cela ne devrait pas dépendre de la configuration car celle-ci appartient à l'application et non à la dll. 

Ceci est expliqué à ici

0
Saravanan

vous pouvez utiliser ce code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace GClass1
{
[Guid("D6F88E95-8A27-4ae6-B6DE-0542A0FC7039")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface _GesGasConnect
{
    [DispId(1)]
    int SetClass1Ver(string version);


}

[Guid("13FE32AD-4BF8-495f-AB4D-6C61BD463EA4")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("InterfacesSMS.Setting")]
public class Class1 : _Class1
{
    public Class1() { }


    public int SetClass1(string version)
    {
        return (DateTime.Today.Day);
    }
}
}
0
David Lopes