Impostazioni.Default. & Lt; property > restituisce sempre il valore predefinito anziché il valore nella memoria permanente (file XML)

StackOverflow https://stackoverflow.com/questions/192641

Domanda

Di recente ho scritto una DLL in C # (.Net 2.0) che contiene una classe che richiede un indirizzo IP. Un mio collega ha modificato la classe per recuperare l'IP da un ".dll.config" File (XML): apparentemente viene generato automaticamente dalle impostazioni dell'applicazione " file creato (Settings1.settings). Il vantaggio di ciò era consentire all'utente finale di modificare l'indirizzo IP nel file XML / config a piacimento.

Sfortunatamente, quando controllo il suo codice dall'albero e provo a compilare (o utilizzare) questo nuovo codice, qualsiasi applicazione che chiama questa DLL ottiene solo il valore predefinito, anziché il valore dal file.

Il costruttore che chiama il file di configurazione è simile al seguente:

    public class form : System.Windows.Forms.Form
    {
        public form()
        {
            // This call is required by the Windows Form Designer.
            InitializeComponent();
            IP = IPAddress.Parse(Settings1.Default.IPAddress);
        }
    }

Ho trovato a riferimento a questo problema nei forum MSDN in cui un utente ha dichiarato:

  

i "vecchi" valori (quelli che definisci in fase di sviluppo) sono codificati. Se il franework non è in grado di accedere o aprire il file di configurazione, utilizzerà invece le impostazioni predefinite. Questo accadrà sempre se usi le impostazioni in una dll.

  1. Questo significa che non riesco a memorizzare un valore esterno per una DLL in un file di configurazione? (Il mio collega ha in qualche modo fatto funzionare questo ...)

  2. Dato che il mio framework sembra non essere in grado di accedere o aprire il file di configurazione, come faccio a capire perché non funziona? O addirittura rilevare quando ciò accade?

Decker : aiuta un po '. Sfortunatamente, sto scrivendo questa DLL su una specifica, quindi in realtà non ho accesso al file di configurazione dell'applicazione. Come noterai sopra, il mio collega ha creato un " Settings 1 .settings " file. Non l'ho capito al momento, ma sembra ora che l'aggiunta di " 1 " lo tiene fuori dallo spazio delle impostazioni di qualsiasi applicazione che lo chiama.

Suppongo che quello che sto cercando di capire sia il motivo per cui la DLL non sembra trovare il file di configurazione che si trova accanto ad esso nella stessa directory. Tracciare il codice passo dopo passo non rivela nulla.

A parte, posso cambiare il "Tipo di output" del mio assemblaggio da " Class Library " a " Applicazione Windows " e aggiungere le seguenti righe all'inizio del mio codice DLL:

    [STAThread]
    public static void Main(string[] args)
    {
        System.Windows.Forms.Application.Run(new form());
    }

Quando eseguo questo, genera un diverso file di configurazione (un ".exe.config") e quello che posso modificare e farlo estrarre i nuovi dati dal file. Quindi sono un po 'confuso. Qualche idea?

È stato utile?

Soluzione

Sto affrontando questo problema esatto in un'applicazione che sto realizzando nel mezzo della prototipazione. Anche se il suggerimento di Decker di hackerare insieme i file di configurazione dovrebbe funzionare, penso che questo sia un trucco manuale piuttosto scomodo da eseguire come parte di un ciclo di generazione. Invece ho deciso che la soluzione più pulita è quella di fare in modo che ogni libreria analizzi il proprio file library.dll.config. Non è ancora perfetto e richiede un po 'di codice extra sulla caldaia, ma sembra essere l'unico modo per aggirare il modo bizantino in cui .Net gestisce questi file app.config.

Altri suggerimenti

Uso questa tecnica in ogni momento. Spesso ho un assemblaggio di librerie che richiede determinate impostazioni, e ho bisogno che siano impostate sia testando i progetti sia il principale "eseguibile". assiemi, siano essi progetti Web o progetti di servizi Windows.

Hai ragione quando crei un file di impostazioni per qualsiasi progetto, aggiunge un file di configurazione dell'applicazione. Il valore immesso per qualsiasi impostazione viene archiviato in due posizioni: il file di configurazione E negli attributi sulle classi create dall'infrastruttura delle impostazioni. Quando non viene trovato un file di configurazione, vengono utilizzati i valori incorporati negli attributi.

Ecco uno snippet che mostra tale attributo:

Ecco uno snippet che mostra il valore predefinito di ConcordanceServicesEndpointName nella classe generata:

    [global::System.Configuration.ApplicationScopedSettingAttribute()]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Configuration.DefaultSettingValueAttribute("InternalTCP")]

    public string ConcordanceServicesEndpointName {
        get {
            return ((string)(this["ConcordanceServicesEndpointName"]));
        }
    }

Quello che vuoi fare è copiare la sezione di configurazione dal file app.config dal progetto assembly della libreria e unirla (con attenzione) nel web.config o app.config applicabile per l'assembly principale. In fase di esecuzione, è l'unico file di configurazione utilizzato.

Ecco un esempio:

<configSections>
    <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
      <section name="LitigationPortal.Documents.BLL.DocumentsBLLSettings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup>
  </configSections>
  <applicationSettings>
    <LitigationPortal.Documents.BLL.DocumentsBLLSettings>
      <setting name="ConcordanceServicesEndpointName" serializeAs="String">
        <value>InternalTCP</value>
      </setting>
    </KayeScholer.LitigationPortal.Documents.BLL.DocumentsBLLSettings>
  </applicationSettings>

Dovresti copiare queste sezioni in " true " file di configurazione.

Ho avuto lo stesso problema da molto tempo - è fastidioso.

Mi piace l'idea di creare il tuo file di configurazione e far analizzare ogni DLL, anche se potrebbe essere ancora facile perdere la modifica della configurazione.

Una cosa che ho fatto in passato per renderlo almeno un po 'più semplice è assicurarsi che eventuali valori di configurazione che il file Setting1.Settings non siano validi.

Ad esempio, ho una classe che utilizza LINQ-To-SQL per parlare con il DB. Quindi ha un file Setting1.settings in cui archivia la stringa di connessione nel database. Il valore predefinito che viene inserito (trascinando le tabelle del database nel designer) è la stringa di connessione del database dev.

Dopo aver creato il file DBML basato sul database di prova, posso accedere e modificare il file delle impostazioni e digitare un nome di database come " FAKE_DATABASE " ;.

In questo modo, se usi la DLL in un altro progetto e poi dimentichi di unire i file di configurazione per aggiungere il valore di configurazione corretto per la DLL, almeno riceverai un errore che dice qualcosa come " Impossibile connettersi a FAKE_DATABASE ".

Naturalmente, se devi lavorare di nuovo con il designer, dovrai riportare il valore al valore del tuo database di sviluppo.

Dolore enorme. Devono cambiarlo in qualche modo.

Apparentemente l'applicazione sta tentando di leggere dal file di configurazione predefinito (che è probabilmente il file di configurazione dell'applicazione). Per essere sicuro, aggiungi la coppia chiave-valore nel file di configurazione della dll al file di configurazione dell'applicazione, esegui l'applicazione e verifica se questa volta viene letta.

Penso di aver appena trovato una spiegazione del perché questo non funziona per la mia DLL e la mia applicazione di test. Ecco l'eccezione conclusiva dal blog di un ragazzo :

  

La soluzione per questo è assicurarsi che l'applicazione e gli assembly di supporto abbiano lo stesso spazio dei nomi o assicurarsi di unire il contenuto di AppName.exe.config e DllName.dll.config (sì quando si compila un .dll ora genera questo file, tuttavia viene ignorato se lo si copia nella directory dell'applicazione e non viene unito automaticamente)

Quindi, o devo mantenere la DLL e l'applicazione nello stesso spazio dei nomi -o-- Devo unire il contenuto del file di configurazione DLL con il file di configurazione dell'applicazione.

(Questo tipo di disfatta non ha lo scopo della DLL? Pensavo che una DLL dovesse essere una libreria indipendente.)

Forse è per questo che funziona per il mio collega. L'applicazione di produzione condivide lo stesso spazio dei nomi della DLL. (La mia app di prova chiaramente non ...)

AGGIORNAMENTO: Mi sono appena seduto di recente con il mio collega e ho parlato di nuovo di questo problema e sembra che non funzionasse nemmeno per lui, ma non se ne era reso conto perché aveva imposta il valore iniziale in modo che corrisponda al dispositivo che stavamo tentando di utilizzare. Quindi, ovviamente, all'inizio sembrava funzionare, ma non appena l'abbiamo distribuito altrove con impostazioni leggermente diverse, si è nuovamente rotto.

Ho riscontrato un problema simile durante l'utilizzo di app.config. Prova a eseguire l'applicazione da .exe anziché da Visual Studio & amp; vedere se poi si comporta come previsto.

È possibile che nella tua DLL tu abbia il modificatore di accesso (per Settings1.Settings) impostato su Internal (Friend for VB). Prova a modificare Access MOdifier in Pubblico e verifica se ciò consente alla tua applicazione di leggere / scrivere valori dalla configurazione di DLL.

La risposta di Howard copre la teoria.

Un modo rapido e sporco per risolvere questo problema è analizzare manualmente il file di configurazione XML.

    string configFile = Assembly.GetExecutingAssembly().Location + ".config";
    XDocument.Load(configFile).Root.Element("appSettings")....

L'errore che penso che tutti voi commettiate è che apparentemente fate riferimento alle Impostazioni DLL tramite Settings1.Default.IPAddress mentre vi viene semplicemente chiesto di fare questo Settings1.IPAddress .

La differenza è che quando si utilizza Settings1.Default.IPAddress i valori vengono ricavati dai valori hardcoded incorporati nel file assembly (.dll o .exe) come Attributo [global :: System. Configuration.DefaultSettingValueAttribute (...)].

Mentre Settings1.IPAddress è il valore modificabile nel file .dll.config (file XML) **. quindi qualsiasi modifica apportata al file XML, non si riflette nel valore predefinito codificato nell'assembly.

Non questo:

IP = IPAddress.Parse(Settings1.Default.IPAddress);

Ma prova questo:

*IP = IPAddress.Parse(Settings1.IPAddress);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top