webentwicklung-frage-antwort-db.com.de

C # DLL Konfigurationsdatei

Ich versuche, eine app.config-Datei zu meiner DLL hinzuzufügen, aber alle Versuche sind fehlgeschlagen. 

Laut MusicGenesis in ' Konfigurationsinformationen in eine DLL ' setzen, sollte dies kein Problem sein. Also mache ich offensichtlich etwas falsch ...

Der folgende Code sollte meinen ConnectionString von meiner DLL zurückgeben:

return ConfigurationManager.AppSettings["ConnectionString"];

Wenn ich jedoch die app.config -Datei in meine Konsolenanwendung kopiere, funktioniert das einwandfrei.

Irgendwelche Ideen?

179
MegaByte

Das Erstellen einer .NET-Konfigurationsdatei für eine .DLL ist nicht trivial, und das aus gutem Grund. Der .NET-Konfigurationsmechanismus verfügt über eine Reihe von Funktionen, die das einfache Aktualisieren/Aktualisieren der App erleichtern und die installierten Apps vor dem Trampeln der anderen Konfigurationsdateien schützen.

Es gibt einen großen Unterschied zwischen der Verwendung von DLL und der Verwendung einer Anwendung. Es ist unwahrscheinlich, dass mehrere Kopien einer Anwendung auf demselben Computer für denselben Benutzer installiert sind. Möglicherweise verfügen Sie jedoch über 100 verschiedene Apps oder Bibliotheken, die alle .NET-DLLs verwenden.

Während es selten erforderlich ist, die Einstellungen für verschiedene Kopien einer App innerhalb eines Benutzerprofils separat zu protokollieren, ist es sehr unwahrscheinlich, dass alle verschiedenen Verwendungen einer DLL die Konfiguration gemeinsam nutzen sollen gegenseitig. Wenn Sie ein Konfigurationsobjekt mit der "normalen" Methode abrufen, ist das Objekt, das Sie zurückerhalten, daher an die Konfiguration der App-Domäne, in der Sie ausgeführt werden, und nicht an die jeweilige Assembly gebunden.

Die App-Domäne ist an die Root-Assembly gebunden, die die Assembly geladen hat, in der sich Ihr Code tatsächlich befindet. In den meisten Fällen handelt es sich dabei um die Assembly Ihrer Haupt-EXE-Datei, die die .DLL-Datei lädt. Es ist möglich, andere Anwendungsdomänen in einer Anwendung zu aktivieren, Sie müssen jedoch explizit Informationen zur Stammassembly dieser Anwendungsdomäne angeben.

Aus diesem Grund ist das Verfahren zum Erstellen einer bibliotheksspezifischen Konfigurationsdatei nicht so bequem. Es ist derselbe Vorgang, den Sie zum Erstellen einer beliebigen portablen Konfigurationsdatei verwenden würden, die nicht an eine bestimmte Assembly gebunden ist, für die Sie jedoch das XML-Schema, den Konfigurationsabschnitt und die Konfigurationselementmechanismen von .NET verwenden möchten. Dies erfordert die Erstellung einer ExeConfigurationFileMap Objekt, das in die Daten geladen wird, um zu ermitteln, wo die Konfigurationsdatei gespeichert wird, und dann ConfigurationManager.OpenMappedExeConfiguration aufgerufen wird, um sie in einer neuen Configuration-Instanz zu öffnen. Dieses Wille schließt Sie vom Versionsschutz ab, den der automatische Pfadgenerierungsmechanismus bietet.

Statistisch gesehen verwenden Sie diese Bibliothek wahrscheinlich in einer hauseigenen Umgebung, und es ist unwahrscheinlich, dass Sie über mehrere Apps innerhalb eines Computers/Anwenders verfügen. Aber Wenn nicht, sollten Sie etwas beachten. Wenn Sie eine einzige globale Konfigurationsdatei für Ihre DLL verwenden, müssen Sie sich unabhängig von der App, auf die sie verweist, um Zugriffskonflikte kümmern. Wenn zwei Apps, die auf Ihre Bibliothek verweisen, zur gleichen Zeit ausgeführt werden und jeweils ein eigenes Configuration-Objekt geöffnet ist, wird beim Speichern der Änderungen beim nächsten Mal, wenn Sie versuchen, Daten in der anderen App abzurufen oder zu speichern, eine Ausnahme ausgelöst.

Der sicherste und einfachste Weg, dies zu umgehen, besteht darin, dass die Assembly, die Ihre DLL lädt, auch einige Informationen über sich selbst liefert, oder durch Untersuchung der App-Domäne der referenzierenden Assembly ermittelt wird. Verwenden Sie diese Option, um eine Art Ordnerstruktur zu erstellen, in der für jede App, die auf Ihre DLL verweist, separate Benutzer-Konfigurationsdateien gespeichert werden.

Wenn Sie bestimmte möchten und globale Einstellungen für Ihre DLL haben möchten, unabhängig davon, wo auf sie verwiesen wird, müssen Sie Ihren Standort dafür bestimmen, anstatt dass .NET automatisch einen geeigneten Ort ermittelt . Sie müssen auch aggressiv beim Verwalten des Zugriffs auf die Datei vorgehen. Sie müssen so viel wie möglich zwischenspeichern, wobei die Configuration-Instanz NUR so lange in der Umgebung verbleibt, wie das Laden oder Speichern erforderlich ist. Sie wird unmittelbar vor dem Öffnen geöffnet und unmittelbar danach entsorgt. Und schließlich benötigen Sie einen Sperrmechanismus, um die Datei zu schützen, während sie von einer der Apps bearbeitet wird, die die Bibliothek verwenden.

268
Chris Ammerman

wenn Sie Einstellungen aus der Konfigurationsdatei der DLL lesen möchten, jedoch nicht aus den Stammanwendungen web.config oder app.config, verwenden Sie den folgenden Code, um die Konfiguration in der DLL zu lesen.

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

Ich hatte das gleiche Problem und suchte mehrere Stunden im Web, konnte aber keine Lösung finden, also habe ich meine eigene gemacht. Ich habe mich gefragt, warum das .net-Konfigurationssystem so unflexibel ist.

Hintergrund: Ich möchte, dass meine DAL.dll über eine eigene Konfigurationsdatei für Datenbank- und DAL-Einstellungen verfügt. Ich benötige auch die app.config für Enterprise Library und eigene Konfigurationen. Ich brauche also sowohl die app.config als auch die dll.config.

Was ich nicht wollte, ist das Passieren aller Eigenschaften/Einstellungen von der App zu meiner DAL-Ebene!

"AppDomain.CurrentDomain.SetupInformation.ConfigurationFile" zu biegen, ist nicht möglich, da ich es für das normale Verhalten von app.config benötige.

Meine Anforderungen/Sichtweisen waren:

  • KEINE manuelle Kopie von ClassLibrary1.dll.config nach WindowsFormsApplication1.exe.config, da dies für andere Entwickler nicht reproduzierbar ist.
  • behalten Sie die Verwendung der starken Eingabe "Properties.Settings.Default.NameOfValue" (Verhalten der Einstellungen) bei, da ich denke, dass dies ein Hauptfeature ist und ich es nicht verlieren wollte
  • Ich habe das Fehlen von ApplicationSettingsBase zum Einfügen Ihrer eigenen/benutzerdefinierten Konfigurationsdatei oder Verwaltung herausgefunden (alle erforderlichen Felder sind in diesen Klassen privat).
  • die Verwendung der "configSource" -Dateidirektion ist nicht möglich, da wir die ClassLibrary1.dll.config kopieren/umschreiben und mehrere XML-Dateien für mehrere Abschnitte bereitstellen müssen (das hat mir auch nicht gefallen)
  • Ich habe nicht gern meinen eigenen SettingsProvider für diese einfache Aufgabe geschrieben, wie MSDN vorschlägt, da ich dachte, das wäre einfach zu viel
  • Ich brauche nur die Abschnitte applicationSettings und connectionStrings aus der Konfigurationsdatei

Ich kam zum Ändern der Settings.cs-Datei und implementierte eine Methode, die ClassLibrary1.dll.config öffnet und die Abschnittsinformationen in einem privaten Feld liest. Danach habe ich "this [string propertyName]" überschrieben, so dass die generierten Settings.Desginer.cs-Aufrufe in meine neue Eigenschaft anstelle der Basisklasse aufgerufen werden. Dort wird die Einstellung aus der Liste ausgelesen. 

Schließlich gibt es folgenden Code:

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;
        }
    }

Sie müssen nur Ihre ClassLibrary1.dll.config aus dem ClassLibrary1-Ausgabeverzeichnis in das Ausgabeverzeichnis Ihrer Anwendung kopieren .. Vielleicht wird es für jemanden nützlich sein. 

19
Sven

Bei der Verwendung von ConfigurationManager bin ich ziemlich sicher, dass die Konfigurationsdatei von process/AppDomain (app.config/web.config) geladen wird. Wenn Sie eine bestimmte Konfigurationsdatei laden möchten, müssen Sie diese Datei speziell nach Name fragen ...

Du könntest es versuchen:

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

ConfigurationManager.AppSettings gibt die für die Anwendung definierten Einstellungen zurück, nicht für die jeweilige DLL. Sie können auf sie zugreifen, aber es werden die Anwendungseinstellungen zurückgegeben.

Wenn Sie Ihre DLL aus einer anderen Anwendung verwenden, muss ConnectionString in den App-Einstellungen der Anwendung enthalten sein.

13
Jorge Córdoba

Ich weiß, dass dies zu spät für die Party ist, aber ich dachte, ich würde die Lösung teilen, die ich für DLLs verwende.

Ich bin mehr von der K.I.S.S. Denkweise, wenn ich also ein .NET DLL habe, das externe Datenpunkte speichern möchte, die steuern, wie es funktioniert oder wo es hingeht usw., erstelle ich einfach eine "config" -Klasse, die nur öffentliche Eigenschaften enthält, die speichern alle Datenpunkte, die es benötigt und die ich außerhalb der DLL steuern lassen möchte, um ein erneutes Kompilieren zu verhindern, um die Änderungen vorzunehmen. Dann verwende ich .Net's XML Serializing, um die Objektdarstellung der Klasse zu speichern und in eine Datei zu laden.

Es gibt viele Möglichkeiten, das Lesen und den Zugriff darauf zu erledigen, von Singleton, einer statischen Dienstprogrammklasse bis zu Erweiterungsmethoden usw. Dies hängt davon ab, wie Ihre DLL strukturiert ist und welche Methode für Ihre DLL am besten.

5
Rodney S. Foley

wenn Sie richtig sind, können Sie die Konfigurationsdatei einer DLL lesen. Ich hatte einen Tag lang Probleme damit, bis ich herausfand, dass meine Konfigurationsdatei das Problem war. Siehe meinen Code unten. es konnte laufen.

        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);

mein Plugin1.dll.config sah wie folgt aus;

<?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>

Ich fand heraus, dass in meiner Konfigurationsdatei das <appSettings>-Tag fehlte. Schauen Sie sich also um, Ihr Problem könnte anders sein, aber nicht so weit von meinem entfernt.

3
mugume david

Da sich die Assembly in einem temporären Cache befindet, sollten Sie den Pfad kombinieren, um die Konfiguration der DLL abzurufen:

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

Die Konfigurationsdateien scheinen verwirrend zu sein, da sich ihr Verhalten von der Entwicklungsumgebung zur Bereitstellung ändert. Anscheinend kann eine DLL über eine eigene Konfigurationsdatei verfügen. Sobald Sie jedoch die DLL (zusammen mit ihrer Konfigurationsdatei) an anderer Stelle kopiert und eingefügt haben, funktioniert das Ganze nicht mehr. Die einzige Lösung besteht darin, die app.config-Dateien manuell in einer einzigen Datei zusammenzuführen, die nur vom Exec verwendet wird. Für z. myapp.exe enthält eine Datei myapp.exe.config, die alle Einstellungen für alle von myapp.exe verwendeten Dlls enthält. Ich verwende VS 2008. 

3
kenny

Wenn Sie Bibliotheken verwenden, die hinter den Kulissen eine große Menge an Konfigurationen wie WCF nachschlagen, sollten Sie Folgendes in Betracht ziehen:

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

Oder in PowerShell:

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

IMO Diese Technik ist ein Codegeruch und eignet sich eigentlich nur für Ad-hoc-Skripte. Wenn Sie dies im Produktionscode tun möchten, ist es vielleicht Zeit für eine Überprüfung der Architektur.

Folgendes wird NICHT empfohlen:
Als technische Neugierde hier eine Variation des Themas. Sie können einen statischen Konstruktor in einer der in der DLL enthaltenen Klassen erstellen und diesen Aufruf von dort aus durchführen. Ich würde dies nur als letzten Ausweg empfehlen. 

3
Paul Williams

Ich habe eine scheinbare Lösung für dieses Problem gefunden. Ich verwende VS 2008 C #. Meine Lösung beinhaltet die Verwendung unterschiedlicher Namespaces zwischen mehreren Konfigurationsdateien. Ich habe die Lösung in meinem Blog veröffentlicht: http://tommiecarter.blogspot.com/2011/02/how-to-access-multiple-config-files-in.html .

Zum Beispiel:

Dieser Namespace liest/schreibt DLL-Einstellungen:

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

Dieser Namespace liest/schreibt die Exe-Einstellungen:

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

Im Artikel werden einige Einschränkungen erwähnt. HTH

2
Tommie C.

Die vollständige Lösung ist nicht oft an einem Ort zu finden ... 

1) Erstellen Sie eine App-Konfigurationsdatei und nennen Sie sie "yourDllName.dll.config".
2) Klicken Sie mit der rechten Maustaste auf die Konfigurationsdatei, die oben in VS Solution Explorer erstellt wurde, und klicken Sie auf Eigenschaften
--- setze "Build Action" = Inhalt
--- setze "Copy To Output Directory" = Immer
3) Fügen Sie der Konfigurationsdatei (yourDllName.dll.config) einen appSettings-Abschnitt mit Ihrem keyName und IhremKeyValue hinzu

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

4) Fügen Sie System.Configuration zu Ihren Referenzen für DLL/Klasse/Projekt hinzu
5) Fügen Sie dem Code die using-Anweisungen hinzu, an denen Sie auf die Konfigurationseinstellung zugreifen möchten

using System.Configuration;
using System.Reflection;

6) um auf den Wert zuzugreifen 

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

7) freut euch, es funktioniert

IMHO sollte dies nur bei der Entwicklung einer neuen DLL/Bibliothek verwendet werden. 

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

Die Konfigurationsdatei stellt eine gute Referenz dar, wenn Sie die appSettings der DLL zu Ihrer eigentlichen Anwendung hinzufügen. 

1
David C Fuchs

Wie Marc sagt, ist dies nicht möglich (obwohl Sie in Visual Studio eine Anwendungskonfigurationsdatei zu einem Klassenbibliothekprojekt hinzufügen können).

Vielleicht möchten Sie die AssemblySettings Klasse auschecken, die Assembly-Konfigurationsdateien möglich zu machen scheint.

1
Gerrie Schenck

In diesem Beitrag wurde ein ähnliches Problem besprochen und mein Problem gelöst. Wie kann eine separate Anwendungseinstellungsdatei dynamisch geladen und mit den aktuellen Einstellungen zusammengeführt werden? könnte hilfreich sein

0
dhailis

Bei einer DLL sollte dies nicht von der Konfiguration abhängen, da die Konfiguration der Anwendung und nicht der DLL gehört. 

Dies wird unter hier erklärt.

0
Saravanan

sie können diesen Code verwenden:

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