File konfigurasi C # DLL

191

Saya mencoba menambahkan file app.config ke DLL saya, tetapi semua upaya gagal.

Menurut MusicGenesis di ' Menempatkan informasi konfigurasi dalam DLL ' ini seharusnya tidak menjadi masalah. Jadi jelas saya melakukan sesuatu yang salah ...

Kode berikut harus mengembalikan ConnectionString dari DLL saya:

return ConfigurationManager.AppSettings["ConnectionString"];

Namun, ketika saya menyalin file app.config ke aplikasi konsol saya, itu berfungsi dengan baik.

Ada ide?

MegaByte
sumber
Menurut posting yang dirujuk: jika nama dll adalah MyDll.dll, maka file konfigurasi harus MyDLL.dll.config. Jadi jika Anda membaca pengaturan konfigurasi dari dalam dll, itu harus merujuk ke konfigurasi sendiri, kan?
MegaByte
11
Tidak masalah apa yang diminta kode - mencari file seperti yang ditentukan untuk AppDomain: AppDomain.CurrentDomain.SetupInformation.ConfigurationFile setting
Marc Gravell
Catatan: Pertanyaan "memasukkan informasi konfigurasi ke dalam DLL" adalah tentang memisahkan kode konfigurasi aplikasi Anda ke pustaka agar tetap terpisah dari kode aplikasi utama. Ini sangat berbeda dari file konfigurasi yang terpisah dan khusus untuk DLL sendiri.
Chris Ammerman
lihat posting ini [masukkan uraian tautan di sini] [1], adalah solusinya bagi saya [1]: stackoverflow.com/questions/2389290/…
dhailis
lihat posting ini [Bagaimana cara memuat file Pengaturan Aplikasi terpisah secara dinamis dan bergabung dengan pengaturan saat ini?] [1] mungkin helpfu [1]: stackoverflow.com/questions/2389290/…
dhailis

Jawaban:

277

Bukan hal sepele untuk membuat file konfigurasi .NET untuk .DLL, dan untuk alasan yang baik. Mekanisme konfigurasi .NET memiliki banyak fitur di dalamnya untuk memudahkan peningkatan / pembaruan aplikasi, dan untuk melindungi aplikasi yang terinstal dari menginjak-injak file konfigurasi satu sama lain.

Ada perbedaan besar antara bagaimana DLL digunakan dan bagaimana aplikasi digunakan. Anda tidak mungkin memiliki banyak salinan aplikasi yang diinstal pada mesin yang sama untuk pengguna yang sama. Tetapi Anda mungkin memiliki 100 aplikasi atau pustaka yang berbeda yang semuanya memanfaatkan beberapa .NET DLL.

Meskipun jarang ada kebutuhan untuk melacak pengaturan secara terpisah untuk salinan aplikasi yang berbeda dalam satu profil pengguna, sangat tidak mungkin bahwa Anda ingin semua penggunaan yang berbeda dari DLL untuk berbagi konfigurasi satu sama lain. Karena alasan ini, ketika Anda mengambil objek Konfigurasi menggunakan metode "normal", objek yang Anda dapatkan terkait dengan konfigurasi App Domain yang Anda jalankan, bukan pada rakitan tertentu.

App Domain terikat ke rakitan root yang memuat rakitan di mana kode Anda sebenarnya. Dalam kebanyakan kasus ini adalah rakitan utama .EXE Anda, yang merupakan apa yang memuat .DLL. Dimungkinkan untuk memutar domain aplikasi lain dalam suatu aplikasi, tetapi Anda harus secara eksplisit memberikan informasi tentang apa rakitan root dari domain aplikasi itu.

Karena semua ini, prosedur untuk membuat file konfigurasi perpustakaan khusus tidak begitu nyaman. Ini adalah proses yang sama yang akan Anda gunakan untuk membuat file konfigurasi portabel sewenang-wenang yang tidak terikat pada perakitan tertentu, tetapi Anda ingin memanfaatkan skema XML .NET, bagian konfigurasi dan mekanisme elemen konfigurasi, dll. Ini mencakup pembuatan ExeConfigurationFileMapobjek. , memuat data untuk mengidentifikasi di mana file config akan disimpan, dan kemudian memanggil ConfigurationManager. OpenMappedExeConfigurationuntuk membukanya menjadi Configurationcontoh baru . Ini akan memotong Anda dari perlindungan versi yang ditawarkan oleh mekanisme pembuatan jalur otomatis.

Secara statistik, Anda mungkin menggunakan pustaka ini dalam pengaturan internal, dan sepertinya Anda tidak akan memiliki banyak aplikasi yang memanfaatkannya dalam satu mesin / pengguna. Tetapi jika tidak, ada sesuatu yang harus Anda ingat. Jika Anda menggunakan satu file konfigurasi global untuk DLL Anda, terlepas dari aplikasi yang mereferensikannya, Anda perlu khawatir tentang konflik akses. Jika dua aplikasi yang mereferensikan pustaka Anda berjalan pada saat yang sama, masing-masing dengan Configurationobjeknya sendiri terbuka, maka ketika satu menyimpan perubahan, itu akan menyebabkan pengecualian saat Anda mencoba mengambil atau menyimpan data di aplikasi lain.

Cara paling aman dan paling sederhana untuk menyiasatinya adalah dengan mengharuskan majelis yang memuat DLL Anda juga memberikan beberapa informasi tentang dirinya sendiri, atau untuk mendeteksinya dengan memeriksa App Domain dari rujukan referensi. Gunakan ini untuk membuat semacam struktur folder untuk menjaga file konfigurasi pengguna terpisah untuk setiap aplikasi yang mereferensikan DLL Anda.

Jika Anda yakin ingin memiliki pengaturan global untuk DLL Anda di mana pun itu direferensikan, Anda harus menentukan lokasi Anda untuk itu daripada. NET mencari yang tepat secara otomatis. Anda juga harus agresif dalam mengelola akses ke file. Anda harus melakukan cache sebanyak mungkin, menjaga Configurationinstance hanya HANYA selama yang diperlukan untuk memuat atau menyimpan, membuka segera sebelum dan membuang segera setelah. Dan akhirnya, Anda akan memerlukan mekanisme kunci untuk melindungi file saat sedang diedit oleh salah satu aplikasi yang menggunakan perpustakaan.

Chris Ammerman
sumber
saya berpikir bahwa mekanisme sinkronisasi harus menjadi "peristiwa bernama" dll, karena itu lintas proses
Jacob
8
: / Meh. Our adalah aplikasi monster enterprise dengan .exe utama yang ditulis oleh orang-orang di zona waktu yang berbeda dan modul yang diwakili oleh berbagai DLL dan secara dinamis terikat melalui kerangka plugin kustom. Semua ini "Anda harus memastikan beberapa aplikasi dapat menggunakan DLL Anda secara simultan" benar-benar salah.
JohnL4
Selain itu, di sebagian besar karir saya, saya telah melihat mekanisme bersama-objek generik yang indah ini sama sekali diabaikan, dengan tim yang membuat DLL (atau JAR) yang hanya dapat digunakan dalam satu konteks (dan harus ada, atau aplikasi gagal) ). Mereka mungkin terikat secara statis, tapi itu sudah ketinggalan jaman.
JohnL4
1
"Secara statistik, Anda mungkin menggunakan perpustakaan ini dalam pengaturan internal, dan sepertinya Anda tidak akan memiliki banyak aplikasi yang memanfaatkannya dalam satu mesin / pengguna." Perbedaan antara teori dan praktik kadang-kadang membuat saya sangat pemarah.
JohnL4
1
@Panzercrisis, fitur Pengaturan Visual Studio.settings secara otomatis membuat jalur khusus versi untuk semua pengaturan pengguna. Lihat: stackoverflow.com/questions/35778528/…
Deantwo
101

jika Anda ingin membaca pengaturan dari file konfigurasi DLL tetapi tidak dari aplikasi root web.config atau app.config gunakan kode di bawah ini untuk membaca konfigurasi di dll.

var appConfig = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
string dllConfigData = appConfig.AppSettings.Settings["dllConfigData"].Value;
Morbia
sumber
Dalam sistem C ++ untuk VS 2008 terkelola :: Konfigurasi :: Konfigurasi ^ appConfig = ConfigurationManager :: OpenExeConfiguration (Assembly :: GetExecutingAssembly () -> Location); String ^ name = appConfig-> AppSettings-> Pengaturan ["name"] -> Value;
Hans
Terima kasih, ini benar-benar menyelesaikan masalah saya. Saya telah menangani masalah ini selama sekitar dua hari, dan tidak membuatnya bekerja sampai sekarang. Saat men-debug sebuah tes, ConfigurationManager membaca dari machine.config -Saya pikir-, karena string koneksi yang ditarik adalah tentang SQLExpress-string koneksi yang tidak saya daftarkan-.
yopez83
19

Saya memiliki masalah yang sama dan mencari di web selama beberapa jam tetapi saya tidak dapat menemukan solusi sehingga saya membuat sendiri. Saya bertanya-tanya mengapa sistem konfigurasi .net sangat tidak fleksibel.

Latar Belakang: Saya ingin memiliki DAL.dll saya untuk memiliki file konfigurasi sendiri untuk pengaturan database dan DAL. Saya juga memerlukan app.config untuk Enterprise Library dan konfigurasinya sendiri. Jadi saya membutuhkan app.config dan dll.config.

Apa yang tidak ingin saya lakukan adalah meneruskan setiap properti / pengaturan dari aplikasi ke lapisan DAL saya!

menekuk "AppDomain.CurrentDomain.SetupInformation.ConfigurationFile" tidak mungkin karena saya memerlukannya untuk perilaku app.config yang normal.

Persyaratan / sudut pandang saya adalah:

  • TIDAK ada salinan manual apa pun dari ClassLibrary1.dll.config ke WindowsFormsApplication1.exe.config karena ini tidak dapat diproduksi kembali untuk pengembang lain.
  • pertahankan penggunaan pengetikan yang kuat "Properties.Settings.Default.NameOfValue" (Perilaku pengaturan) karena saya pikir ini adalah fitur utama dan saya tidak ingin kehilangannya
  • Saya menemukan kekurangan ApplicationSettingsBase untuk menyuntikkan file / manajemen konfigurasi / kustom Anda sendiri (semua bidang yang diperlukan bersifat pribadi di kelas-kelas ini)
  • penggunaan pengalihan file "configSource" tidak dimungkinkan karena kami harus menyalin / menulis ulang ClassLibrary1.dll.config dan menyediakan beberapa file XML untuk beberapa bagian (saya juga tidak suka ini)
  • Saya tidak suka menulis SettingsProvider saya sendiri untuk tugas sederhana ini seperti yang disarankan MSDN karena saya pikir itu terlalu banyak
  • Saya hanya perlu bagian applicationSettings dan connectionStrings dari file konfigurasi

Saya datang dengan memodifikasi file Settings.cs dan menerapkan metode yang membuka ClassLibrary1.dll.config dan membaca informasi bagian dalam bidang pribadi. Setelah itu, saya mengesampingkan "this [string propertyName]" sehingga panggilan Settings.Desginer.cs dihasilkan ke Properti baru saya alih-alih kelas dasar. Di sana pengaturan dibaca dari Daftar.

Akhirnya ada kode berikut:

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

Anda hanya perlu menyalin ClassLibrary1.dll.config Anda dari direktori output ClassLibrary1 ke direktori output aplikasi Anda. Mungkin seseorang akan merasakan manfaatnya.

Sven
sumber
14

Saat menggunakan ConfigurationManager, saya cukup yakin itu memuat file proses / AppDomainkonfigurasi (app.config / web.config). Jika Anda ingin memuat file konfigurasi tertentu, Anda harus secara khusus meminta file itu dengan nama ...

Kamu bisa mencoba:

var config = ConfigurationManager.OpenExeConfiguration("foo.dll");
config.ConnectionStrings. [etc]
Marc Gravell
sumber
Menurut posting yang dirujuk: jika nama dll adalah MyDll.dll, maka file konfigurasi harus MyDLL.dll.config. Jadi, jika Anda membaca pengaturan konfigurasi dari dalam dll, itu harus merujuk ke konfigurasi sendiri, kan?
MegaByte
1
Tidak ... kurasa tidak. "from with the etc." tidak membuat masalah; secara default, ini mencari file config yang didefinisikan untuk AppDomain: my.exe.config
Marc Gravell
1
Secara khusus, pengaturan AppDomain.CurrentDomain.SetupInformation.ConfigurationFile.
Marc Gravell
Catatan: Saya mencoba OpenExeConfiguration, dan saya juga tidak yakin itu berhasil. Mungkin hanya menggabungkan konfigurasi dengan app.config?
Marc Gravell
Itu bisa dilakukan ... tetapi tidak dengan dukungan dan keamanan yang sama seperti file app.config untuk EXE. Lihat jawaban saya.
Chris Ammerman
13

ConfigurationManager.AppSettings mengembalikan pengaturan yang ditentukan untuk aplikasi, bukan untuk DLL tertentu, Anda dapat mengaksesnya tetapi pengaturan aplikasi yang akan dikembalikan.

Jika Anda menggunakan Anda dll dari aplikasi lain maka ConnectionString harus di app.settings aplikasi.

Jorge Córdoba
sumber
6

Saya tahu ini terlambat ke pesta, namun saya pikir saya akan membagikan solusi yang saya gunakan untuk DLL.

Saya lebih dari aliran pemikiran KISS, jadi ketika saya memiliki .NET DLL yang ingin menyimpan titik data eksternal yang mengontrol cara kerjanya atau ke mana ia pergi, dll. Saya hanya membuat kelas "config" yang hanya memiliki properti publik yang menyimpan semua titik data yang dibutuhkan dan bahwa saya ingin dapat mengontrol eksternal ke DLL untuk mencegah kompilasi ulang untuk membuat perubahan. Kemudian saya menggunakan .Net's XML Serializing untuk menyimpan dan memuat representasi objek dari kelas ke file.

Ada banyak cara untuk menangani membacanya dan mengaksesnya, dari Singleton, kelas utilitas statis, hingga metode ekstensi, dll. Ini tergantung pada bagaimana DLL Anda disusun dan metode apa yang paling cocok untuk DLL Anda.

Rodney S. Foley
sumber
Saya menggunakan pendekatan ini juga dan saya senang dengan cara kerjanya sejauh ini.
Dave
4

Anda benar, Anda dapat membaca file konfigurasi dll. Saya berjuang dengan ini selama satu hari sampai saya menemukan bahwa file konfigurasi saya adalah masalahnya. Lihat kode saya di bawah ini. itu bisa berjalan.

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

saya Plugin1.dll.configmelihat seperti di bawah ini;

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

Saya menemukan bahwa file konfigurasi saya tidak memiliki <appSettings>tag, jadi lihat-lihat, masalah Anda mungkin berbeda tetapi tidak begitu jauh dari saya.

mugume david
sumber
3

Karena rakitan berada di cache sementara, Anda harus menggabungkan jalur untuk mendapatkan konfigurasi dll:

var appConfig = ConfigurationManager.OpenExeConfiguration(
    Path.Combine(Environment.CurrentDirectory, Assembly.GetExecutingAssembly().ManifestModule.Name));
Lin Song Yang
sumber
alih-alih "Path.Combine (Environment.CurrentDirectory, Assembly.GetExecutingAssembly (). ManifestModule.Name)" Anda dapat menggunakan "Assembly.GetExecutingAssembly (). Location"
Cadburry
3

Jika Anda menggunakan pustaka yang mencari sejumlah besar pengaduan di belakang layar, seperti WCF, Anda dapat mempertimbangkan melakukan ini:

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

Atau di PowerShell:

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

IMO teknik ini adalah bau kode dan benar-benar hanya cocok untuk digunakan dalam skrip ad hoc. Jika Anda mendapati diri Anda ingin melakukan ini dalam kode produksi, mungkin sekarang saatnya untuk tinjauan arsitektur.

Berikut ini TIDAK dianjurkan:
Sebagai keingintahuan teknis, inilah variasi pada tema. Anda dapat membuat konstruktor statis di dalam salah satu kelas yang bertempat di DLL, dan membuat panggilan ini dari sana. Saya tidak akan merekomendasikan melakukan ini kecuali sebagai pilihan terakhir.

Paul Williams
sumber
3

Solusi lengkap tidak sering ditemukan di satu tempat ...

1) Buat file konfigurasi aplikasi dan beri nama "yourDllName.dll.config"
2) Klik kanan pada file konfigurasi yang dibuat di atas di VS Solution Explorer, klik properti
--- set "Build Action" = Konten
--- set "Salin Ke Direktori Output" = Selalu
3) Tambahkan bagian appSettings ke file konfigurasi (yourDllName.dll.config) dengan yourKeyName dan yourKeyValue Anda

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

4) Tambahkan System.Configuration ke dll / kelas / referensi proyek Anda
5) Tambahkan pernyataan menggunakan ke kode Anda di mana Anda bermaksud untuk mengakses pengaturan konfigurasi

using System.Configuration;
using System.Reflection;

6) Untuk mengakses nilai

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

7) bersukacita, itu berhasil

IMHO, ini seharusnya hanya digunakan ketika mengembangkan dll / perpustakaan baru.

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

File konfigurasi akhirnya menjadi referensi yang bagus, karena ketika Anda menambahkan pengaturan aplikasi dll ke aplikasi Anda yang sebenarnya.

David C Fuchs
sumber
3

Sepertinya file konfigurasi ini benar-benar membingungkan untuk diklarifikasi karena perilaku mereka berubah dari lingkungan dev ke penyebaran. Rupanya DLL dapat memiliki file konfigurasi sendiri, tetapi begitu Anda menyalin dan menempelkan dll (bersama dengan file konfigurasi mereka) di tempat lain, semuanya berhenti bekerja. Satu-satunya solusi adalah dengan menggabungkan file app.config secara manual menjadi satu file, yang hanya akan digunakan oleh eksekutif. Misalnya, myapp.exe akan memiliki file myapp.exe.config yang berisi semua pengaturan untuk semua dll yang digunakan oleh myapp.exe. Saya menggunakan VS 2008.

kenny
sumber
2

Saya telah menemukan apa yang tampaknya merupakan solusi yang baik untuk masalah ini. Saya menggunakan VS 2008 C #. Solusi saya melibatkan penggunaan ruang nama yang berbeda antara beberapa file konfigurasi. Saya telah memposting solusinya di blog saya: http://tommiecarter.blogspot.com/2011/02/how-to-access-multiple-config-files-in.html .

Sebagai contoh:

Namespace ini membaca / menulis pengaturan dll:

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

Namespace ini membaca / menulis pengaturan exe:

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

Ada beberapa peringatan yang disebutkan dalam artikel. HTH

Tommie C.
sumber
1

Seperti kata Marc, ini tidak mungkin (walaupun Visual Studio memungkinkan Anda untuk menambahkan file konfigurasi aplikasi dalam proyek perpustakaan kelas).

Anda mungkin ingin memeriksa kelas AssemblySettings yang tampaknya memungkinkan file konfigurasi perakitan.

Gerrie Schenck
sumber
0

Untuk dll, seharusnya tidak tergantung pada konfigurasi karena konfigurasi dimiliki oleh aplikasi dan bukan oleh dll.

Ini dijelaskan di sini

Saravanan
sumber
0

Anda dapat menggunakan kode ini:

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
sumber