File di configurazione DLL C #


191

Sto cercando di aggiungere un file app.config alla mia DLL, ma tutti i tentativi sono falliti.

Secondo MusicGenesis in " Inserimento delle informazioni di configurazione in una DLL " questo non dovrebbe essere un problema. Quindi ovviamente sto facendo qualcosa di sbagliato ...

Il seguente codice dovrebbe restituire il mio ConnectionString dalla mia DLL:

return ConfigurationManager.AppSettings["ConnectionString"];

Tuttavia, quando copio il file app.config nella mia applicazione console, funziona benissimo.

Qualche idea?


Secondo il post di riferimento: se il nome della dll era MyDll.dll, il file di configurazione dovrebbe essere MyDLL.dll.config. Quindi, se leggi le impostazioni di configurazione all'interno della dll, dovrebbe fare riferimento alla propria configurazione, giusto?
MegaByte,

11
Non importa quale codice richiede: sta cercando il file come specificato per AppDomain: AppDomain.CurrentDomain.SetupInformation.ConfigurationFile setting
Marc Gravell

Nota: la domanda "inserire le informazioni di configurazione in una DLL" riguarda la separazione del codice di configurazione dell'app in una libreria per tenerlo separato dal codice dell'app principale. Questo è molto diverso da un file di configurazione separato e speciale per una DLL da solo.
Chris Ammerman,

vedere questo post [entra Descrizione Link qui] [1], è stata la soluzione per me [1]: stackoverflow.com/questions/2389290/...
dhailis

vedere questo post [Come caricare un file in modo dinamico e si fondono separata Impostazioni applicazione con le impostazioni correnti?] [1] potrebbe essere helpfu [1]: stackoverflow.com/questions/2389290/...
dhailis

Risposte:


277

Non è banale creare un file di configurazione .NET per un .DLL, e per buoni motivi. Il meccanismo di configurazione .NET ha molte funzionalità integrate per facilitare l'upgrade / aggiornamento dell'app e per proteggere le app installate dal calpestare i file di configurazione degli altri.

C'è una grande differenza tra il modo in cui viene utilizzata una DLL e il modo in cui viene utilizzata un'applicazione. È improbabile che più copie di un'applicazione siano installate sullo stesso computer per lo stesso utente. Ma potresti avere ben 100 app o librerie diverse che fanno uso di alcune DLL .NET.

Mentre raramente è necessario tenere traccia delle impostazioni separatamente per diverse copie di un'app all'interno di un profilo utente, è molto improbabile che si desideri che tutti i diversi usi di una DLL condividano la configurazione tra loro. Per questo motivo, quando si recupera un oggetto Configuration utilizzando il metodo "normale", l'oggetto che si ottiene è legato alla configurazione del dominio app in cui si esegue, anziché al particolare assembly.

Il dominio app è associato all'assembly root che ha caricato l'assembly in cui si trova effettivamente il codice. Nella maggior parte dei casi si tratterà dell'assemblaggio del file .EXE principale, che è ciò che ha caricato il .DLL. È possibile eseguire il rollup di altri domini di app all'interno di un'applicazione, ma è necessario fornire esplicitamente informazioni sull'assemblaggio root di quel dominio di app.

Per questo motivo, la procedura per la creazione di un file di configurazione specifico della libreria non è così conveniente. È lo stesso processo che useresti per creare un file di configurazione portatile arbitrario non legato ad alcun particolare assembly, ma per il quale vuoi usare lo schema XML, la sezione di configurazione e i meccanismi degli elementi di configurazione di .NET, ecc. Ciò comporta la creazione di un ExeConfigurationFileMapoggetto , caricando i dati per identificare dove verrà archiviato il file di configurazione e quindi chiamando ConfigurationManager.OpenMappedExeConfigurationper aprirlo in una nuova Configurationistanza. Questo vi interromperla dalla protezione versione offerta dal meccanismo automatico di generazione del percorso.

Statisticamente parlando, probabilmente stai usando questa libreria in un ambiente interno, ed è improbabile che tu abbia più app che la usano all'interno di una macchina / utente. In caso contrario, c'è qualcosa che dovresti tenere a mente. Se si utilizza un singolo file di configurazione globale per la DLL, indipendentemente dall'app a cui fa riferimento, è necessario preoccuparsi dei conflitti di accesso. Se due app che fanno riferimento alla tua libreria sono in esecuzione contemporaneamente, ognuna con il proprio Configurationoggetto aperto, quindi quando si salvano le modifiche, si verificherà un'eccezione la prossima volta che si tenta di recuperare o salvare i dati nell'altra app.

Il modo più sicuro e semplice per aggirare il problema è richiedere che l'assembly che sta caricando la DLL fornisca anche alcune informazioni su se stesso o rilevarlo esaminando il dominio app dell'assembly di riferimento. Usalo per creare una sorta di struttura di cartelle per mantenere file di configurazione utente separati per ogni app che fa riferimento alla tua DLL.

Se sei sicuro di voler avere impostazioni globali per la tua DLL, indipendentemente da dove viene referenziata, dovrai determinare la tua posizione per essa piuttosto che .NET trovarne una appropriata automaticamente. Dovrai anche essere aggressivo nella gestione dell'accesso al file. Dovrai memorizzare nella cache il più possibile, mantenendo l' Configurationistanza SOLO per tutto il tempo necessario per caricare o salvare, aprendo immediatamente prima e eliminando immediatamente dopo. Infine, avrai bisogno di un meccanismo di blocco per proteggere il file mentre viene modificato da una delle app che utilizzano la libreria.


penso che il meccanismo di sincronizzazione dovrebbe essere un "evento denominato", ecc., poiché è un processo
multiplo

8
: / Meh. La nostra è un'app monster enterprise con il principale .exe scritto da ragazzi in un fuso orario diverso e i moduli rappresentati da varie DLL e associati dinamicamente attraverso un framework di plug-in personalizzato. Tutto questo "dovrai assicurarti che più app possano usare la tua DLL contemporaneamente" pomposity è esattamente sbagliato.
JohnL4,

Inoltre, in gran parte della mia carriera, ho visto questi adorabili meccanismi generici di oggetti condivisi completamente ignorati, con i team che creavano DLL (o JAR) che possono essere utilizzati solo in un contesto (e devono essere presenti, o l'app non riesce ). Potrebbero anche essere staticamente vincolati, ma questo è passe.
JohnL4,

1
"Statisticamente parlando, probabilmente stai usando questa libreria in un ambiente interno, ed è improbabile che tu abbia più app che la usano all'interno di una sola macchina / utente." La differenza tra teoria e pratica mi rende piuttosto scontroso a volte.
JohnL4,

1
@Panzercrisis, la funzione Settings.settings di Visual Studio crea automaticamente percorsi specifici della versione per tutte le impostazioni dell'utente. Vedi: stackoverflow.com/questions/35778528/...
Deantwo

101

se si desidera leggere le impostazioni dal file di configurazione della DLL ma non dalle applicazioni root web.config o app.config, utilizzare il codice seguente per leggere la configurazione nella dll.

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

Nel C ++ gestito per VS 2008 System :: Configuration :: Configuration ^ appConfig = ConfigurationManager :: OpenExeConfiguration (Assembly :: GetExecutingAssembly () -> Location); String ^ name = appConfig-> AppSettings-> Settings ["name"] -> Value;
Hans

Grazie, questo ha davvero risolto il mio problema. Ho affrontato questo problema per circa due giorni e non ho funzionato fino ad ora. Come debug di un test, ConfigurationManager stava leggendo da machine.config -Penso-, poiché le stringhe di connessione estratte riguardavano SQLExpress -connection string che non avevo elencato-.
yopez83,

19

Ho avuto lo stesso problema e ho cercato sul web per diverse ore ma non sono riuscito a trovare alcuna soluzione, quindi ne ho creato uno mio. Mi chiedevo perché il sistema di configurazione .net sia così poco flessibile.

Sfondo: Voglio che il mio DAL.dll abbia il proprio file di configurazione per il database e le impostazioni DAL. Ho anche bisogno dell'app.config per Enterprise Library e delle sue configurazioni. Quindi ho bisogno sia di app.config che di dll.config.

Quello che non volevo fare è passare attraverso tutte le proprietà / impostazioni dall'app al mio livello DAL!

piegare "AppDomain.CurrentDomain.SetupInformation.ConfigurationFile" non è possibile perché ne ho bisogno per il normale comportamento app.config.

I miei requisiti / punti di vista erano:

  • Nessuna copia manuale di nulla da ClassLibrary1.dll.config a WindowsFormsApplication1.exe.config perché non è riproducibile per altri sviluppatori.
  • conservare l'uso della digitazione forte "Properties.Settings.Default.NameOfValue" (comportamento delle impostazioni) perché penso che questa sia una caratteristica importante e non volevo perderla
  • Ho scoperto la mancanza di ApplicationSettingsBase per iniettare il proprio file di configurazione / gestione (tutti i campi necessari sono privati ​​in queste classi)
  • l'uso del reindirizzamento dei file "configSource" non è possibile perché dovremmo copiare / riscrivere ClassLibrary1.dll.config e fornire diversi file XML per diverse sezioni (anche questo non mi è piaciuto)
  • Non mi piaceva scrivere il mio SettingsProvider per questo semplice compito come suggerisce MSDN perché pensavo che sarebbe stato semplicemente troppo
  • Ho solo bisogno di sezioni applicationSettings e connectionStrings dal file di configurazione

Mi è venuta in mente la modifica del file Settings.cs e ho implementato un metodo che apre ClassLibrary1.dll.config e legge le informazioni della sezione in un campo privato. Dopodiché, ho scavalcato "this [string propertyName]", così il Settings.Desginer.cs generato chiama nella mia nuova proprietà anziché nella classe base. Lì l'impostazione viene letta dall'elenco.

Infine c'è il seguente codice:

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

Dovrai semplicemente copiare ClassLibrary1.dll.config dalla directory di output ClassLibrary1 alla directory di output dell'applicazione. Forse qualcuno lo troverà utile.


14

Quando utilizzo ConfigurationManager, sono abbastanza sicuro che stia caricando il processo /AppDomain file di configurazione (app.config / web.config). Se si desidera caricare un file di configurazione specifico, è necessario richiedere tale file in base al nome ...

Puoi provare:

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

Secondo il post di riferimento: se il nome della dll era MyDll.dll, il file di configurazione dovrebbe essere MyDLL.dll.config. Quindi, se leggi le impostazioni di configurazione all'interno della dll, dovrebbe fare riferimento alla propria configurazione, giusto?
MegaByte,

1
No ... io non la penso così. "from with the dll" non fa probabilità; per impostazione predefinita, sta esaminando il file di configurazione definito per AppDomain: my.exe.config
Marc Gravell

1
In particolare, l'impostazione AppDomain.CurrentDomain.SetupInformation.ConfigurationFile.
Marc Gravell

nota: ho provato OpenExeConfiguration e non sono nemmeno sicuro che funzioni. Forse unisci la configurazione con app.config?
Marc Gravell

Esso può essere fatto ... ma non con lo stesso tipo di sostegno e di sicurezza, come il file app.config per un file EXE. Vedi la mia risposta
Chris Ammerman,

13

ConfigurationManager.AppSettings restituisce le impostazioni definite per l'applicazione, non per la DLL specifica, è possibile accedervi ma saranno le impostazioni dell'applicazione che verranno restituite.

Se stai usando la tua DLL da un'altra applicazione, ConnectionString deve trovarsi nelle impostazioni dell'app dell'applicazione.


6

So che è tardi per la festa, tuttavia ho pensato di condividere la soluzione che uso per le DLL.

Sono più della scuola di pensiero KISS, quindi quando ho una DLL .NET che vuole archiviare punti di dati esterni che controllano come funziona o dove va, ecc. Creo semplicemente una classe "config" che ha solo proprietà pubbliche che memorizza tutti i punti dati necessari e che vorrei poter controllare all'esterno della DLL per impedire la ricompilazione per apportare le modifiche. Quindi uso la serializzazione XML di .Net per salvare e caricare la rappresentazione dell'oggetto della classe in un file.

Esistono molti modi per gestire la lettura e accedervi, da un Singleton, una classe di utilità statica, ai metodi di estensione, ecc. Questo dipende da come è strutturata la DLL e quale metodo si adatterà meglio alla DLL.


Uso anche questo approccio e sono contento del modo in cui ha funzionato finora.
Dave,

4

hai ragione, puoi leggere il file di configurazione di una dll. Ho lottato con questo per un giorno fino a quando ho scoperto che il mio file di configurazione era il problema. Vedi il mio codice qui sotto. è stato in grado di correre.

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

il mio Plugin1.dll.configsembrava come sotto;

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

Ho scoperto che il mio file di configurazione mancava del <appSettings>tag, quindi guardati intorno, il tuo problema avrebbe potuto essere diverso ma non così lontano dal mio.


3

Poiché l'assembly risiede in una cache temporanea, è necessario combinare il percorso per ottenere la configurazione della dll:

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

invece di "Path.Combine (Environment.CurrentDirectory, Assembly.GetExecutingAssembly (). ManifestModule.Name)" puoi usare "Assembly.GetExecutingAssembly (). Location"
Cadburry

3

Se stai usando librerie che cercano una grande quantità di configenze dietro le quinte, come WCF, potresti prendere in considerazione di fare ciò:

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

O in PowerShell:

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

IMO questa tecnica è un odore di codice ed è davvero adatta solo per l'uso in script ad hoc. Se ti trovi a voler farlo nel codice di produzione, forse è il momento di una revisione dell'architettura.

Non è consigliabile
quanto segue: come curiosità tecnica, ecco una variazione sul tema. È possibile creare un costruttore statico all'interno di una delle classi ospitate nella DLL ed effettuare questa chiamata da lì. Non consiglierei di farlo, tranne come ultima risorsa.


3

La soluzione completa non si trova spesso in un unico posto ...

1) Creare un file di configurazione dell'app e denominarlo "yourDllName.dll.config"
2) Fare clic con il pulsante destro del mouse sul file di configurazione creato sopra in VS Solution Explorer, fare clic su proprietà
--- set "Build Action" = Contenuto
--- imposta "Copia nella directory di output" = Sempre
3) Aggiungi una sezione AppSettings al file di configurazione (yourDllName.dll.config) con yourKeyName e yourKeyValue

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

4) Aggiungi System.Configuration ai tuoi riferimenti dll / class / project
5) Aggiungi le istruzioni using al tuo codice dove intendi accedere alle impostazioni di configurazione

using System.Configuration;
using System.Reflection;

6) Per accedere al valore

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

7) rallegrati, funziona

IMHO, questo dovrebbe essere usato solo quando si sviluppa una nuova dll / libreria.

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

Il file di configurazione finisce per essere un ottimo riferimento, per quando aggiungi le impostazioni dell'app della dll alla tua vera applicazione.


3

Sembra che questo file di configurazione sia davvero confuso da chiarire quando il loro comportamento cambia dall'ambiente di sviluppo alla distribuzione. Apparentemente una DLL può avere il suo file di configurazione, ma una volta che hai copiato e incollato la dll (insieme al loro file di configurazione) altrove, il tutto ha smesso di funzionare. L'unica soluzione è quella di unire manualmente i file app.config in un singolo file, che verrà utilizzato solo da exec. Ad esempio, myapp.exe avrà un file myapp.exe.config che contiene tutte le impostazioni per tutte le DLL utilizzate da myapp.exe. Sto usando VS 2008.


2

Ho trovato quella che sembra una buona soluzione a questo problema. Sto usando VS 2008 C #. La mia soluzione prevede l'uso di spazi dei nomi distinti tra più file di configurazione. Ho pubblicato la soluzione sul mio blog: http://tommiecarter.blogspot.com/2011/02/how-to-access-multiple-config-files-in.html .

Per esempio:

Questo spazio dei nomi legge / scrive le impostazioni dll:

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

Questo spazio dei nomi legge / scrive le impostazioni di exe:

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

Ci sono alcuni avvertimenti menzionati nell'articolo. HTH


1

Come dice Marc, questo non è possibile (anche se Visual Studio consente di aggiungere un file di configurazione dell'applicazione in un progetto di libreria di classi).

Potresti voler controllare la classe AssemblySettings che sembra rendere possibili i file di configurazione dell'assembly.



0

Per una dll, non dovrebbe dipendere dalla configurazione poiché la configurazione è di proprietà dell'applicazione e non della dll.

Questo è spiegato qui


0

puoi usare questo codice:

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);
    }
}
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.