Entspricht 'app.config' für eine Bibliothek (DLL)

149

Gibt es ein Äquivalent zu app.configfür Bibliotheken (DLLs)? Wenn nicht, wie lassen sich Konfigurationseinstellungen, die für eine Bibliothek spezifisch sind, am einfachsten speichern? Bitte beachten Sie, dass die Bibliothek in verschiedenen Anwendungen verwendet werden kann.

Louis Rhys
quelle

Antworten:

161

Sie können eine separate Konfigurationsdatei haben, diese muss jedoch "manuell" ConfigurationManager.AppSettings["key"]gelesen werden. Dadurch wird nur die Konfiguration der laufenden Assembly gelesen.

Angenommen, Sie verwenden Visual Studio als IDE, können Sie mit der rechten Maustaste auf das gewünschte Projekt klicken → Hinzufügen → Neues Element → Anwendungskonfigurationsdatei

Dies wird App.configdem Projektordner hinzugefügt , und geben Sie Ihre Einstellungen dort unter <appSettings>Abschnitt ein. Wenn Sie Visual Studio nicht verwenden und die Datei manuell hinzufügen, geben Sie ihr den folgenden Namen: DllName.dll.config . Andernfalls funktioniert der folgende Code nicht ordnungsgemäß.

Nun aus dieser Datei zu lesen haben folgende Funktion:

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

Und um es zu benutzen:

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");
    ...
}

Sie müssen auch einen Verweis auf den System.Configuration-Namespace hinzufügen, damit die ConfigurationManager-Klasse verfügbar ist.

Wenn Sie das Projekt DllName.dll.configerstellen, haben Sie neben der DLL auch eine Datei, die Sie mit der DLL selbst veröffentlichen müssen.

Das obige Beispiel ist ein grundlegender Beispielcode. Wenn Sie an einem vollständigen Beispiel interessiert sind, lesen Sie bitte diese andere Antwort .

Der Schatten-Assistent ist das Ohr für Sie
quelle
1
@ Rodney versuchen, string exeConfigPath = this.GetType().Assembly.Location;zu etwas wie zu ändern :string exeConfigPath = @"C:\MyFolder\DllFolder\ExeName.exe";
Schatten-Assistent ist Ohr für Sie
1
Haben Sie eine Idee, wie Sie dies tun können, wenn die DLL vom Resharper-Unit-Test-Tool in einen unbekannten Ordner kopiert wird?
Autodidakt
11
Ein Tipp für alle anderen, die dies implementieren: Um die Generierung von DllName.dll.config durch Verweisen auf Anwendungen zu automatisieren, habe ich app.config einfach in DllName.dll.config umbenannt und die Eigenschaft "In Ausgabeverzeichnis kopieren" in "Immer kopieren" geändert. . Außerdem benötigte ich Verbindungszeichenfolgen, die mit config.ConnectionStrings.ConnectionStrings [connStringName] .ConnectionString abgerufen werden können.
Jeff G
2
Der app.cfg-Dateiname ist sehr wichtig, um die appcfg-Werte zu lesen. Der Dateiname sollte "DLL_NAME.DLL.CONFIG" sein
SaddamBinSyed
2
Korrektur zu meinem letzten Kommentar. Wenn ich in meiner VS2017-Lösung meine neuen, nicht funktionierenden App.config-Dateien aus meinen Test- und DLL-Projekten entferne und sie einfach wieder zu meinem Testprojekt hinzufüge, funktioniert sie plötzlich! Meine App.config-Einstellung wird jetzt automatisch in die DLL.configs aufgenommen. Was für eine Erleichterung!
Zeek2
30

Leider können Sie nur eine app.config-Datei pro ausführbarer Datei haben. Wenn Sie also DLLs mit Ihrer Anwendung verknüpft haben, können diese keine eigenen app.config-Dateien haben.

Die Lösung lautet: Sie müssen die Datei App.config nicht in das Projekt der Klassenbibliothek einfügen.
Sie fügen die Datei App.config in die Anwendung ein, die auf die DLL Ihrer Klassenbibliothek verweist.

Nehmen wir zum Beispiel an, wir haben eine Klassenbibliothek namens MyClasses.dll, die die Datei app.config wie folgt verwendet:

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

Angenommen, wir haben eine Windows-Anwendung namens MyApp.exe, die auf MyClasses.dll verweist. Es würde eine App.config mit einem Eintrag wie dem folgenden enthalten:

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

ODER

Eine XML-Datei ist am besten für app.config geeignet. Verwenden Sie xml serialize / deserialize nach Bedarf. Sie können es so nennen, wie Sie wollen. Wenn Ihre Konfiguration "statisch" ist und nicht geändert werden muss, können Sie sie auch als eingebettete Ressource zum Projekt hinzufügen.

Hoffe, es gibt eine Idee

PawanS
quelle
6
ConfigurationSettingsist jetzt veraltet und ersetzt durch ConfigurationManager, also wäre das Äquivalent jetztConfigurationManager.AppSettings
Gone Coding
2
Abstimmung nach unten. Die Frage ist pro DLL und nicht pro App. beste Lösung: stackoverflow.com/a/5191101/2935383
Raiserle
3
Ich vermute, dass dieser Vorschlag bei spät gebundenen DLLs, die keine Kenntnis von der ausführbaren Datei haben, die sie aufruft, nicht funktioniert.
Beanmf
9

Konfigurationsdateien sind anwendungsbezogen und nicht montagebezogen. Daher müssen Sie die Konfigurationsabschnitte Ihrer Bibliothek in die Konfigurationsdatei jeder Anwendung einfügen, die Ihre Bibliothek verwendet.

Es ist jedoch nicht empfehlenswert, die Konfiguration aus der Konfigurationsdatei der Anwendung, insbesondere dem appSettingsAbschnitt, in einer Klassenbibliothek abzurufen. Wenn Ihre Bibliothek Parameter benötigt, sollten diese wahrscheinlich als Methodenargumente in Konstruktoren, Factory-Methoden usw. von jedem übergeben werden, der Ihre Bibliothek aufruft. Dies verhindert, dass aufrufende Anwendungen versehentlich Konfigurationseinträge wiederverwenden, die von der Klassenbibliothek erwartet wurden.

XML-Konfigurationsdateien sind jedoch äußerst praktisch. Der beste Kompromiss, den ich gefunden habe, ist die Verwendung benutzerdefinierter Konfigurationsabschnitte. Sie können die Konfiguration Ihrer Bibliothek in eine XML-Datei einfügen, die vom Framework automatisch gelesen und analysiert wird, und Sie vermeiden mögliche Unfälle.

Sie können mehr über benutzerdefinierte Konfigurationsabschnitte auf MSDN erfahren, und auch Phil Haack hat einen schönen Artikel darüber.

madd0
quelle
7
"Es ist keine gute Praxis, die Konfiguration aus einer Konfigurationsdatei in einer Klassenbibliothek abzurufen" - dem stimme ich überhaupt nicht zu. Beispielsweise sollte eine DAL-Klassenbibliothek normalerweise Konfigurationsdaten wie Verbindungszeichenfolgen aus der Anwendungskonfigurationsdatei abrufen, anstatt diese Informationen von der BLL-Schicht übergeben zu lassen. Alle Framework-Klassen, die Konfiguration verwenden (z. B. ASP.NET-Mitgliedschaft), funktionieren auf diese Weise.
Joe
Ich habe meine Antwort leicht geändert. Ich stehe immer noch zu dem, was ich gesagt habe, aber Sie haben Recht, ich wollte nie implizieren, dass Konfigurationsdateien überhaupt nicht verwendet werden sollten. Was ich damit meinte war, dass appSettingsbenutzerdefinierte Abschnitte anstelle von Konventionen eine großartige Alternative bieten. es ist schließlich so ziemlich das, was die ASP.NET-Mitgliedschaft verwendet.
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
}

Nur um etwas zu tun, habe ich die Top-Antwort in eine Klasse umgestaltet. Die Verwendung ist so etwas wie:

ConfigMan configMan = new ConfigMan(this.GetType().Assembly.Location);
var setting = configMan.GetAppSetting("AppSettingsKey");
Feuergarten
quelle
4

Wenn Sie einem Klassenbibliotheksprojekt in Visual Studio Einstellungen hinzufügen (Projekteigenschaften, Einstellungen), wird Ihrem Projekt eine app.config-Datei mit den entsprechenden Abschnitten userSettings / applyatioNSettings und den Standardwerten für diese Einstellungen aus Ihren Settings.settings hinzugefügt Datei.

Diese Konfigurationsdatei wird jedoch nicht zur Laufzeit verwendet. Stattdessen verwendet die Klassenbibliothek die Konfigurationsdatei ihrer Hostanwendung.

Ich glaube, der Hauptgrund für das Generieren dieser Datei ist, dass Sie die Einstellungen kopieren / in die Konfigurationsdatei der Hostanwendung einfügen können.

Joe
quelle
4

Ich erstelle derzeit Plugins für eine Software-Marke für den Einzelhandel, bei denen es sich tatsächlich um .net-Klassenbibliotheken handelt. Voraussetzung ist, dass jedes Plugin mithilfe einer Konfigurationsdatei konfiguriert wird. Nach ein wenig Recherche und Testen habe ich die folgende Klasse zusammengestellt. Es macht den Job einwandfrei. Beachten Sie, dass ich in meinem Fall keine lokale Ausnahmebehandlung implementiert habe, da ich Ausnahmen auf einer höheren Ebene abfange.

Möglicherweise sind einige Anpassungen erforderlich, um den Dezimalpunkt im Fall von Dezimalstellen und Doppelwerten richtig zu machen, aber es funktioniert gut für meine 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);
    }
}

Beispiel für eine App.Config-Datei

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

Verwendung:

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

Dank an Shadow Wizard & MattC

Yiannis Leoussis
quelle
1
Dies sollte die akzeptierte Antwort sein. Sehr kompakt und "funktioniert sofort". Gutes Zeug
Nmarler
2

Als Antwort auf die ursprüngliche Frage füge ich normalerweise die Konfigurationsdatei in meinem Testprojekt als Link hinzu. Anschließend können Sie das Attribut DeploymentItem verwenden, um es dem Ordner Out des Testlaufs hinzuzufügen.

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

Als Antwort auf die Kommentare, dass Baugruppen nicht projektspezifisch sein können, können sie dies und es bietet eine große Flexibilität, insbesondere. bei der Arbeit mit IOC-Frameworks.

Allan Elder
quelle
2

Ich hatte das gleiche Problem und löste es, indem ich Parametersnach dem Hinzufügen einer Anwendungskonfigurationsdatei zum Projekt eine statische Klasse erstellte :

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

Dann erhalten Sie einen Parameter wie folgt:

Parameters.GetParameter("keyName");
krlzlx
quelle
1
Brillant! Dies hat mir geholfen, meine automatisierten Windows-Anwendungstreiber-Tests auf Zielcomputern auszuführen. Die DLLs in meinem Fall stammten aus einem Testprojekt. Das einzige, was ich hinzufügen möchte, ist, dass in Win App Driver (und möglicherweise in anderen Formen des automatisierten Testens) das BaseDirectory tatsächlich der Ausgabeordner ist, der sich jedes Mal ändert. Ich musste einen Teilstring wie diesen erstellen ... AppDomain.CurrentDomain.BaseDirectory.Substring (0, AppDomain.CurrentDomain.BaseDirectory.IndexOf ("TestResults")). Auf diese Weise konnte ich den unerwünschten Ausgabeordner ausschneiden, da sich meine Konfigurationsdatei im selben Ordner wie meine Test-DLLs befand.
Ewan
1

Assemblys haben keine eigene app.config-Datei. Sie verwenden die Datei app.config der Anwendung, die sie verwendet. Wenn Ihre Assembly bestimmte Dinge in der Konfigurationsdatei erwartet, stellen Sie einfach sicher, dass die Konfigurationsdatei Ihrer Anwendung diese Einträge enthält.

Wenn Ihre Assembly von mehreren Anwendungen verwendet wird, muss jede dieser Anwendungen diese Einträge in ihrer Datei app.config haben.

Ich würde Ihnen empfehlen, beispielsweise Eigenschaften für die Klassen in Ihrer Assembly für diese Werte zu definieren

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

Hier erhält die Eigenschaft ExternalServicesUrl ihren Wert aus der Konfigurationsdatei der Anwendung. Wenn einer Anwendung, die diese Assembly verwendet, diese Einstellung in der Konfigurationsdatei fehlt, wird eine Ausnahme angezeigt. Es ist klar, dass etwas fehlte.

MissingConfigFileAppSettings ist eine benutzerdefinierte Ausnahme. Möglicherweise möchten Sie eine andere Ausnahme auslösen.

Ein besseres Design wäre natürlich, wenn die Methode dieser Klassen diese Werte als Parameter bereitstellt, anstatt sich auf die Einstellung der Konfigurationsdatei zu verlassen. Auf diese Weise können die Anwendungen, die diese Klassen verwenden, entscheiden, wo und wie sie diese Werte bereitstellen.

Shiv Kumar
quelle
Vorsichtsmaßnahme: Wenn Sie xUnit-Tests in Ihrer .NET Assembly-DLL ausführen, liest xUnit zur Laufzeit die .config der Bibliothek. Außerdem wird jede App.config ignoriert, die dem Test- oder DLL-Projekt hinzugefügt wurde.
Zeek2
1

Verwenden Sie Vorhandenes Element hinzufügen und wählen Sie die App-Konfiguration aus dem DLL-Projekt aus. Bevor Sie auf Hinzufügen klicken, verwenden Sie den kleinen Abwärtspfeil auf der rechten Seite der Schaltfläche Hinzufügen, um "Als Link hinzufügen".

Ich mache das die ganze Zeit in meinem Entwickler.

GhostJago
quelle
1

Präambel : Ich verwende NET 2.0.

Die von Yiannis Leoussis veröffentlichte Lösung ist akzeptabel, aber ich hatte ein Problem damit.

Erstens gibt die static AppSettingsSection AppSettings = (AppSettingsSection)myDllConfig.GetSection("appSettings");Null zurück. Ich musste es ändernstatic AppSettingSection = myDllConfig.AppSettings;

Dann hat der return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);keinen Haken für Ausnahmen. Also habe ich es geändert

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

Dies funktioniert sehr gut, aber wenn Sie eine andere DLL haben, müssen Sie den Code für jede Assembly jedes Mal neu schreiben. Dies ist also meine Version für eine Klasse, die Sie jedes Mal instanziieren können, wenn Sie sie benötigen.

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

Für eine Konfiguration:

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

Verwenden Sie es als:

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
quelle
Bitte überprüfen Sie die Abstimmung zur Löschung. Mein Fehler war, die Antwort beim Schreiben zu senden.
Matteo Gaggiano
0

Soweit mir bekannt ist, müssen Sie die gewünschten Abschnitte aus der Bibliothek .config kopieren und in die .config-Datei der Anwendung einfügen. Sie erhalten nur 1 app.config pro ausführbarer Instanz.

Mike
quelle
Wenn Sie benutzerdefinierte Konfigurationsabschnitte verwenden, können Sie das Attribut configSource verwenden: <MySection configSource = "mysection.config" /> und die Konfigurationsdatei nur mit DLL kopieren
Jan Remunda
Ich habe neue Fragen hinzugefügt, z. B. zu der Funktion, die immer eine leere Zeichenfolge zurückgibt, und zu Mail-Server-Einstellungen> stackoverflow.com/questions/25123544/… und> stackoverflow.com/questions/25138788/…, also hoffe ich, dass jemand so wie ich antwortet Ich bin fast am Rande der Hardcodierung der Werte in die DLL!
MonkeyMagix
0

Warum nicht verwenden:

  • [ProjectNamespace].Properties.Settings.Default.[KeyProperty] für C #
  • My.Settings.[KeyProperty] für VB.NET

Sie müssen diese Eigenschaften nur zur Entwurfszeit visuell aktualisieren durch:

[Solution Project]->Properties->Settings

Pedro Mora
quelle
Dadurch wird automatisch eine Konfigurationsdatei für die DLL erstellt. Sie können jedoch zur Laufzeit keine geänderten Werte aus der Konfigurationsdatei lesen. Schließlich werden die Werte Ihrer aufrufenden Anwendung angezeigt. Siehe auch @ Joe Antwort
Code Papst
Nein, wenn es für die Konfiguration des Benutzers konfiguriert ist. Die Idee ist, die Anforderungen des Benutzers zu bearbeiten, sie zur Laufzeit zu konfigurieren und dann zu speichern. Wenn der Benutzer dann mit der Bibliothek arbeitet, lädt er seine Konfiguration, die in seinem jeweiligen Benutzerpfad gespeichert ist, funktioniert jedoch nur für ihn.
Pedro Mora
0

Die Verwendung von Konfigurationen muss wie folgt sehr einfach sein:

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

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

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

Weitere Details finden Sie unter MiniConfig

Rahmat Anjirabi
quelle