Fichier de configuration DLL C #

191

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

Selon MusicGenesis dans « Mettre les informations de configuration dans une DLL », cela ne devrait pas être un 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?

MegaByte
la source
Selon le message référé: si le nom de la dll était MyDll.dll, le fichier de configuration devrait être MyDLL.dll.config. Donc, si vous lisez les paramètres de configuration à partir de la dll, il devrait se référer à son propre droit de configuration?
MegaByte
11
Peu importe ce que le code demande - il recherche le fichier spécifié pour le paramètre AppDomain: AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
Marc Gravell
Remarque: la question «Mettre les informations de configuration dans une DLL» concerne la séparation du code de configuration de votre application dans une bibliothèque pour la séparer du code principal de l'application. Ceci est très différent d'un fichier de configuration séparé et spécial pour une DLL seule.
Chris Ammerman
voir ce post [entrez la description du lien ici] [1], était la solution pour moi [1]: stackoverflow.com/questions/2389290/…
dhailis
voir cet article [Comment charger dynamiquement un fichier de paramètres d'application distinct et fusionner avec les paramètres actuels?] [1] pourrait être utile [1]: stackoverflow.com/questions/2389290/…
dhailis

Réponses:

277

Il n'est pas anodin de créer un fichier de configuration .NET pour un .DLL, et pour une bonne raison. Le mécanisme de configuration .NET contient de nombreuses fonctionnalités intégrées pour faciliter la mise à niveau / mise à jour facile de l'application et pour protéger les applications installées contre le piétinement des fichiers de configuration les uns des autres.

Il existe une grande différence entre la façon dont une DLL est utilisée et la façon dont une application est utilisée. Il est peu probable que plusieurs copies d'une application soient installées sur la même machine 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 profil utilisateur, il est très peu probable que vous souhaitiez que toutes les différentes utilisations d'une DLL partagent la configuration entre elles. Pour cette raison, lorsque vous récupérez un objet 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 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 réellement votre code. Dans la plupart des cas, il s'agira de l'assembly de votre .EXE principal, qui a chargé le .DLL. Il est possible de faire tourner d'autres domaines d'application dans une application, mais vous devez explicitement fournir des informations sur l'assembly racine de ce domaine d'application.

À cause de tout cela, la procédure de création d'un fichier de configuration spécifique à la bibliothèque n'est pas si pratique. C'est le même processus que vous utiliseriez pour créer un fichier de configuration portable arbitraire non lié à un assembly particulier, mais pour lequel vous souhaitez utiliser le schéma XML, la section de configuration et les mécanismes d'élément de configuration de .NET, etc. Cela implique la création d'un ExeConfigurationFileMapobjet , chargement des données pour identifier où le fichier de configuration sera stocké, puis appel ConfigurationManager. OpenMappedExeConfigurationpour l'ouvrir dans une nouvelle Configurationinstance. Ce va vous couper de la protection de la version offerte par le mécanisme de génération de chemin automatique.

Statistiquement parlant, vous utilisez probablement cette bibliothèque dans un cadre interne, et il est peu probable que plusieurs applications l'utilisent sur une seule machine / utilisateur. Mais sinon, il y a quelque chose que vous devez garder à l'esprit. Si vous utilisez un seul fichier de configuration global pour votre DLL, quelle que soit l'application qui la référence, vous devez vous soucier des conflits d'accès. Si deux applications référençant votre bibliothèque s'exécutent en même temps, chacune avec leur propreConfiguration objet ouvert, alors quand on enregistre les modifications, cela provoquera une exception la prochaine fois que vous essayez de récupérer ou d'enregistrer des données dans l'autre application.

Le moyen le plus sûr et le plus simple de contourner ce problème est d'exiger que l'assembly qui charge votre DLL fournisse également des informations sur lui-même, ou de le détecter en examinant le domaine d'application de l'assembly de référence. Utilisez-le pour créer une sorte de structure de dossiers pour conserver des fichiers de configuration utilisateur distincts pour chaque application référençant votre DLL.

Si vous êtes certain de vouloir disposer de paramètres globaux pour votre DLL, quel que soit l'endroit où elle est référencée, vous devrez déterminer votre emplacement pour celle-ci plutôt que .NET pour en trouver automatiquement une appropriée. Vous devrez également être agressif dans la gestion de l'accès au fichier. Vous aurez besoin de mettre en cache autant que possible, en gardant l' Configurationinstance UNIQUEMENT le temps nécessaire pour charger ou enregistrer, ouvrir immédiatement avant et éliminer immédiatement après. Et enfin, vous aurez besoin d'un mécanisme de verrouillage pour protéger le fichier pendant qu'il est modifié par l'une des applications qui utilisent la bibliothèque.

Chris Ammerman
la source
Je pense que le mécanisme de synchronisation devrait être un "événement nommé", etc., parce que c'est à travers les processus
Jacob
8
: / Meh. La nôtre est une application d'entreprise monstre avec le .exe principal écrit par des gars dans un fuseau horaire différent et les modules représentés par diverses DLL et liés dynamiquement via un framework de plugins personnalisé. Tout cela "vous devrez vous assurer que plusieurs applications peuvent utiliser votre DLL simultanément" pomposity est exactement faux.
JohnL4
De plus, dans une grande partie de ma carrière, j'ai vu ces adorables mécanismes génériques d'objets partagés complètement ignorés, avec des équipes créant des DLL (ou JAR) qui ne peuvent être utilisées que dans un seul contexte (et doivent être présentes, ou l'application échoue. ). Ils pourraient tout aussi bien être liés statiquement, mais c'est passé.
JohnL4
1
"Statistiquement parlant, vous utilisez probablement cette bibliothèque dans un environnement interne, et il est peu probable que plusieurs applications l'utilisent sur une même machine / utilisateur." La différence entre la théorie et la pratique me rend parfois assez grincheux.
JohnL4
1
@Panzercrisis, la fonctionnalité Settings.settings de Visual Studio crée automatiquement des chemins d'accès spécifiques à la version pour tous les paramètres utilisateur. Voir: stackoverflow.com/questions/35778528/…
Deantwo
101

si vous souhaitez lire les paramètres à partir du fichier de configuration de la DLL mais pas à partir 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;
Morbia
la source
Dans C ++ géré pour VS 2008 System :: Configuration :: Configuration ^ appConfig = ConfigurationManager :: OpenExeConfiguration (Assembly :: GetExecutingAssembly () -> Location); String ^ name = appConfig-> AppSettings-> Settings ["name"] -> Value;
Hans
Merci, cela a vraiment résolu mon problème. Je traite ce problème depuis environ deux jours et je ne l'ai pas fait fonctionner jusqu'à maintenant. Lors du débogage d'un test, ConfigurationManager lisait à partir du fichier machine.config -je pense-, puisque les chaînes de connexion extraites concernaient SQLExpress -connection string que je n'avais pas listée-.
yopez83
19

J'ai eu le même problème et j'ai cherché sur le Web pendant plusieurs heures, mais je n'ai pas trouvé de solution alors j'ai créé la mienne. Je me suis demandé pourquoi le système de configuration .net est si inflexible.

Contexte: Je souhaite 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 du app.config pour Enterprise Library et de ses propres configurations. J'ai donc besoin à la fois de app.config et dll.config.

Ce que je ne voulais pas faire, c'est transmettre toutes les propriétés / paramètres 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 à WindowsFormsApplication1.exe.config car cela n'est pas reproductible pour les autres développeurs.
  • conserver l'utilisation du typage fort "Properties.Settings.Default.NameOfValue" (comportement des paramètres) car je pense que c'est une fonctionnalité majeure et je ne voulais pas la perdre
  • J'ai découvert le manque d'ApplicationSettingsBase pour injecter votre propre fichier de configuration ou de gestion personnalisé (tous les champs nécessaires sont privés dans ces classes)
  • l'utilisation de la redirection de fichiers "configSource" n'est pas possible car nous aurions à copier / réécrire le ClassLibrary1.dll.config et fournir plusieurs fichiers XML pour plusieurs sections (je n'ai pas non plus aimé cela)
  • 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

J'ai proposé de modifier le fichier Settings.cs et mis en œuvre une méthode qui ouvre le ClassLibrary1.dll.config et lit les informations de section dans un champ privé. Après cela, j'ai remplacé "this [string propertyName]" pour que le Settings.Desginer.cs généré appelle dans ma nouvelle propriété au lieu de la classe de base. Là, le paramètre est lu dans 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;
        }
    }

Il vous suffit de 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.

Sven
la source
14

Lorsque vous utilisez ConfigurationManager, je suis à peu près sûr qu'il charge le processus /AppDomain fichier de configuration (app.config / web.config). Si vous souhaitez charger un fichier de configuration spécifique, vous devrez spécifiquement demander ce fichier par son nom ...

Tu pourrais essayer:

var config = ConfigurationManager.OpenExeConfiguration("foo.dll");
config.ConnectionStrings. [etc]
Marc Gravell
la source
Selon le message référé: si le nom de la dll était MyDll.dll, le fichier de configuration devrait être MyDLL.dll.config. Donc, si vous lisez les paramètres de configuration à partir de la dll, il devrait se référer à son propre droit de configuration?
MegaByte
1
Non je ne pense pas. "from with the dll" ne fait aucune chance; par défaut, il regarde le fichier de configuration défini pour l'AppDomain: my.exe.config
Marc Gravell
1
En particulier, le paramètre AppDomain.CurrentDomain.SetupInformation.ConfigurationFile.
Marc Gravell
Remarque: j'ai essayé OpenExeConfiguration et je ne suis pas sûr que cela fonctionne non plus. Peut-être simplement fusionner la configuration avec le app.config?
Marc Gravell
Cela peut être fait ... mais pas avec le même type de support et de sécurité que le fichier app.config pour un EXE. Voyez ma réponse.
Chris Ammerman
13

ConfigurationManager.AppSettings renvoie les paramètres définis pour l'application, pas pour la DLL spécifique, vous pouvez y accéder mais ce sont les paramètres de l'application qui seront renvoyés.

Si vous utilisez votre dll à partir d'une autre application, la ConnectionString doit se trouver dans app.settings de l'application.

Jorge Córdoba
la source
6

Je sais que c'est en retard à la fête, mais j'ai pensé partager la solution que j'utilise pour les DLL.

Je fais plus partie de l'école de pensée KISS, donc quand j'ai une DLL .NET qui veut stocker des points de données externes qui contrôlent son fonctionnement ou sa destination, 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 j'aimerais pouvoir contrôler en externe à la DLL pour éviter de la recompiler pour apporter les modifications. Ensuite, j'utilise la sérialisation XML de .Net pour enregistrer et charger la représentation objet de la classe dans un fichier.

Il existe de nombreuses façons de gérer sa lecture et d'y accéder, depuis un Singleton, une classe d'utilitaire statique, jusqu'aux méthodes d'extension, etc. Cela dépend de la structure de votre DLL et de la méthode qui conviendra le mieux à votre DLL.

Rodney S. Foley
la source
J'utilise également cette approche et je suis satisfait de la façon dont cela a fonctionné jusqu'à présent.
Dave
4

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 je découvre que mon 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.configregardé 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 mon fichier de configuration ne comportait pas de <appSettings>balise, alors regardez autour de vous, votre problème aurait pu être différent mais pas si loin du mien.

Mugume David
la source
3

Étant donné que 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));
Lin Song Yang
la source
au lieu de "Path.Combine (Environment.CurrentDirectory, Assembly.GetExecutingAssembly (). ManifestModule.Name)", vous pouvez utiliser "Assembly.GetExecutingAssembly (). Location"
Cadburry
3

Si vous utilisez des bibliothèques qui recherchent une grande quantité de configuration en arrière-plan, telles que WCF, vous pouvez envisager de faire ceci:

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

Ou dans PowerShell:

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

IMO, cette technique est une odeur de code et ne convient vraiment que pour une utilisation dans des scripts ad hoc. Si vous souhaitez le faire dans le code de production, il est peut-être temps de passer en revue l'architecture.

Ce qui suit n'est PAS recommandé:
Par 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.

Paul Williams
la source
3

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" = Content
--- set "Copy To Output Directory" = Always
3) Ajoutez une section appSettings au fichier de configuration (yourDllName.dll.config) avec votre nomKeyName 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 dll / classe / projet
5) Ajoutez les instructions using à votre code là où vous avez l'intention d'accéder au paramètre de configuration

using System.Configuration;
using System.Reflection;

6) Pour 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, lorsque vous ajoutez les appSettings de la DLL à votre application réelle.

David C Fuchs
la source
3

Il semble que ces fichiers de configuration soient vraiment difficiles à 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 leur fichier de configuration) ailleurs, tout a cessé de fonctionner. La seule solution est de fusionner manuellement les fichiers app.config en un seul fichier, qui ne sera utilisé que par l'exécutif. Par exemple, myapp.exe aura un fichier myapp.exe.config contenant tous les paramètres de toutes les dll utilisées par myapp.exe. J'utilise VS 2008.

Kenny
la source
2

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;

Il y a quelques mises en garde mentionnées dans l'article. HTH

Tommie C.
la source
1

Comme le dit Marc, ce n'est pas possible (bien que Visual Studio vous permette 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 possible les fichiers de configuration d'assembly.

Gerrie Schenck
la source
0

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

Ceci est expliqué ici

Saravanan
la source
0

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);
    }
}
}
David Lopes
la source