Еквівалентно "app.config" для бібліотеки (DLL)


149

Чи є еквівалент app.configбібліотекам (DLL)? Якщо ні, то який найпростіший спосіб зберігати налаштування конфігурації, характерні для бібліотеки? Зверніть увагу, що бібліотека може використовуватися в різних програмах.

Відповіді:


161

Ви можете мати окремий файл конфігурації, але вам доведеться читати його "вручну", він ConfigurationManager.AppSettings["key"]буде читати лише конфігурацію запущеної збірки.

Припустимо, що ви використовуєте Visual Studio як IDE, ви можете клацнути правою кнопкою миші потрібний проект → Додати → Новий елемент → Файл конфігурації програми

Це додасться App.configдо папки проекту, розмістить там свої параметри під <appSettings>розділом. Якщо ви не використовуєте Visual Studio і додаєте файл вручну, переконайтесь, що йому дано таке ім'я: DllName.dll.config , інакше наведений нижче код не працюватиме належним чином.

Тепер для читання з цього файлу є така функція:

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

І використовувати його:

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

Вам також доведеться додати посилання на простір імен System.Configuration, щоб мати доступний клас ConfigurationManager.

Під час створення проекту, крім DLL, ви також будете мати DllName.dll.configфайл, це файл, який ви повинні опублікувати разом із самою DLL.

Наведене вище - основний зразок коду, для тих, хто зацікавлений у повномасштабному прикладі, зверніться до цієї іншої відповіді .


1
@Rodney спробуйте змінити string exeConfigPath = this.GetType().Assembly.Location;щось на кшталт:string exeConfigPath = @"C:\MyFolder\DllFolder\ExeName.exe";
Shadow Wizard is Ear For You

1
Будь-яка ідея, як це зробити, якщо dll копіюється в якусь невідому папку інструментом тестування блоку resharper?
Автододаток

11
Порада для всіх, хто реалізує це: щоб автоматизувати генерацію DllName.dll.config шляхом посилання на додатки, я просто перейменував app.config на DllName.dll.config і змінив властивість "Копіювати у вихідний каталог" на "Копіювати завжди" . Також моя потреба полягала в з'єднанні рядків, які можна отримати за допомогою config.ConnectionStrings.ConnectionStrings [connStringName] .ConnectionString.
Джефф Г

2
ім'я файлу app.cfg дуже важливо, щоб прочитати значення appcfg, ім'я файлу має бути "DLL_NAME.DLL.CONFIG"
SaddamBinSyed

2
Виправлення мого останнього коментаря. У моєму рішенні VS2017, видаливши нові мої непрацюючі файли App.config з моїх тестових та DLL-проектів і просто повторно додавши його до мого тестового проекту, він раптом починає працювати! Налаштування App.config тепер автоматично включається в DLL.configs. Яке полегшення!
Zeek2

30

На жаль, у вас може бути лише один файл app.config на виконаний файл, тож якщо у вашій програмі зв'язані DLL, вони не можуть мати власних файлів app.config.

Рішення полягає в тому, що вам не потрібно ставити файл App.config в проект бібліотеки класів.
Ви поміщаєте файл App.config у додаток, який посилається на dll бібліотеки класів.

Наприклад, скажімо, у нас є бібліотека класів з назвою MyClasses.dll, яка використовує файл app.config так:

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

Скажімо, у нас є додаток Windows з назвою MyApp.exe, на яке посилається MyClasses.dll. Він міститиме App.config із записом, таким як:

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

АБО

Xml-файл найкращий еквівалент app.config. Використовуйте xml серіалізувати / десеріалізувати за потребою. Ви можете назвати його тим, що хочете. Якщо ваш конфігурація "статична" і не потребує змін, ви також можете додати її до проекту як вбудований ресурс.

Сподіваюся, це дає певну ідею


6
ConfigurationSettingsтепер застарілий і замінений на ConfigurationManager, тому еквівалент був би заразConfigurationManager.AppSettings
Пройшов кодування

2
голосування вниз. питання на dll, а не на додаток. Краще рішення: stackoverflow.com/a/5191101/2935383
raiserle

3
Я підозрюю, що ця пропозиція не спрацює у випадку запізнілих dll, які не мали б знання про виконувану програму, яка викликає їх.
beanmf

9

Файли конфігурації залежать від додатків, а не в межах монтажу. Тому вам потрібно буде розмістити розділи конфігурації вашої бібліотеки у файлі конфігурації кожного додатка, який використовує вашу бібліотеку.

Однак, це не дуже добра практика отримання конфігурації з файлу конфігурації програми, особливо з appSettingsрозділу, в бібліотеці класів. Якщо вашій бібліотеці потрібні параметри, вони, ймовірно, повинні передаватися як аргументи методів у конструкторах, фабричних методах тощо тим, хто викликає вашу бібліотеку. Це запобігає виклику додатків від випадкового використання записів конфігурації, очікуваних бібліотекою класів.

Однак, файли конфігурації XML надзвичайно зручні, тому найкращий компроміс, який я знайшов, - це використання спеціальних розділів конфігурації. Ви можете помістити конфігурацію вашої бібліотеки у XML-файл, який автоматично зчитується та аналізується рамкою, і ви уникаєте потенційних аварій.

Ви можете дізнатися більше про розділи конфігурації на MSDN, а також про Філа Хаака є чудова стаття про них.


7
"Недобра практика отримати конфігурацію з файлу конфігурації в бібліотеці класів" - я категорично не згоден з цим. Наприклад, бібліотека класів DAL повинна зазвичай отримувати дані конфігурації, такі як рядки з'єднання, з файлу конфігурації програми, а не передавати цю інформацію з рівня BLL. Будь-які класи Framework, які використовують конфігурацію (наприклад, ASP.NET Membership), працюють таким чином.
Джо

Я трохи змінив свою відповідь. Я все ще стояв за тим, що я сказав, але ти маєш рацію, я ніколи не мав на увазі, що файли конфігурації взагалі не повинні використовуватися. Я мав на увазі те, що замість конвенцій appSettingsспеціальні розділи пропонують чудову альтернативу; Це майже все, чим користується членство ASP.NET.
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
}

Тільки для того, щоб щось зробити, я відновив верхню відповідь у класі. Використання - це щось на зразок:

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

4

Якщо ви додасте Налаштування до проекту бібліотеки класів у Visual Studio (Властивості проекту, Налаштування), він додасть файл app.config до вашого проекту з відповідними розділами UserSettings / applicatioNettings та значеннями за замовчуванням для цих налаштувань із параметрів Settings.settings. файл.

Однак цей файл конфігурації не буде використовуватися під час виконання - натомість бібліотека класів використовує файл конфігурації свого хостинг-програми.

Я вважаю, що головна причина для створення цього файлу полягає в тому, що ви можете скопіювати / вставити налаштування у файл конфігурації хост-програми.


4

Наразі я створюю плагіни для роздрібної торгової марки програмного забезпечення, які фактично є бібліотеками класу .net. Як вимогу, кожен плагін повинен бути налаштований за допомогою файлу config. Після невеликих досліджень та тестувань я склав наступний клас. Вона робить роботу бездоганно. Зауважте, що в моєму випадку я не застосував локальну обробку винятків, тому що я виловлюю винятки на більш високому рівні.

Можливо, потрібні певні налаштування, щоб визначити десяткову точку у випадку десятків і подвійних значень, але це добре справляється з моєю культурою ...

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

Зразок файлу App.Config

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

Використання:

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

Кредити Shadow Wizard & MattC


1
Це має бути прийнятою відповіддю. Дуже компактний і «працює прямо з коробки». Хороший матеріал
nmarler

2

У відповідь на початкове запитання я зазвичай додаю конфігураційний файл у свій тестовий проект як посилання; потім можна використовувати атрибут DeploymentItem для додавання до папки Out тестового запуску.

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

У відповідь на зауваження, що Асамблеї не можуть бути конкретними для проекту, вони можуть, і це забезпечує велику гнучкість особливо. при роботі з рамками МОК.


2

Я зіткнувся з тією ж проблемою і вирішив її, створивши статичний клас Parametersпісля додавання файлу конфігурації програми до проекту:

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

Потім отримайте такий параметр:

Parameters.GetParameter("keyName");

1
Блискуче! Це допомогло мені отримати автоматичний тест драйвера додатків Windows, який працює на цільових машинах. Кольори в моєму випадку були з тестового проекту. Єдине, що я хотів би додати, це те, що у драйвері Win App (і, можливо, інших формах автоматизованого тестування) BaseDirectory - це фактично папка виводу, яка змінюється щоразу. Мені довелося виконати підрядку так: AppDomain.CurrentDomain.BaseDirectory.Substring (0, AppDomain.CurrentDomain.BaseDirectory.IndexOf ("TestResults")). таким чином я міг вирізати небажану папку виводу, оскільки мій конфігураційний файл знаходився в тій самій папці, що і мої тестові dlls.
Еван

1

Асамблеї не мають власного файлу app.config. Вони використовують файл app.config програми, яка їх використовує. Отже, якщо ваша збірка очікує певних речей у конфігураційному файлі, тоді просто переконайтеся, що у файлі конфігурації програми є ці записи.

Якщо ваша збірка використовується декількома додатками, тоді для кожного з цих програм потрібно буде мати ці записи у своєму файлі app.config.

Що б я рекомендував вам зробити, це визначити властивості класів у вашій збірці для цих значень, наприклад

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

Тут властивість ExternalServicesUrl отримує своє значення з конфігураційного файла програми. Якщо в будь-якій програмі, що використовує цю збірку, відсутнє це налаштування у конфігураційному файлі, ви отримаєте виняток.

MissingConfigFileAppSettings - це спеціальний виняток. Ви можете кинути інший виняток.

Звичайно, кращою конструкцією було б, щоб метод цих класів надав ці значення в якості параметрів, а не спирався на налаштування файлу конфігурації. Таким чином програми, що використовують ці класи, можуть вирішувати, де і як вони надають ці значення.


Зверніть увагу на це: під час запуску тестів xUnit на вашій .NET збірці DLL, xUnit буде читати .config бібліотеки під час виконання. І він буде ігнорувати будь-який додаток App.config, доданий до тестового або DLL-проекту.
Zeek2

1

Використовуйте додавання існуючого елемента, виберіть конфігурацію програми з DLL проекту. Перш ніж натиснути кнопку "Додати", скористайтеся стрілкою вниз праворуч від кнопки "Додати", щоб "додати як посилання"

Я роблю це весь час у своєму деві.


1

Преамбула : я використовую NET 2.0;

Рішення, розміщене Yiannis Leoussis, є прийнятним, але у мене виникли певні проблеми.

По-перше, static AppSettingsSection AppSettings = (AppSettingsSection)myDllConfig.GetSection("appSettings");повертає нуль. Мені довелося це змінитиstatic AppSettingSection = myDllConfig.AppSettings;

Тоді return (T)Convert.ChangeType(AppSettings.Settings[name].Value, typeof(T), nfi);немає вилучень для Винятку. Так я це змінив

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

Це працює дуже добре, але якщо у вас інший dll, вам доведеться переписувати кожен раз код для кожної збірки. Отож, це моя версія для класу, що дозволяє інстанціювати кожен раз, коли вам потрібно.

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

Для конфігурації:

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

Використовуйте його як:

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

Перегляньте голосування щодо видалення. Моєю помилкою було надіслати відповідь під час її написання.
Маттео Гаджіано

0

Наскільки мені відомо, ви повинні скопіювати + вставити потрібні розділи з бібліотеки .config у файл .config програми. Ви отримуєте лише 1 app.config за виконаний екземпляр.


якщо ви використовуєте власні розділи конфігурації, ви можете використовувати атрибут configSource: <MySection configSource = "mysection.config" /> та конфігураційний файл копіювати лише з dll
Jan Remunda

Я додав нові запитання як запитання, наприклад, щодо функції, яка завжди повертає порожні рядки та налаштування сервера пошти> stackoverflow.com/questions/25123544/… та> stackoverflow.com/questions/25138788/…, тому я сподіваюся, що хтось відповість на них як я Я майже на межі просто жорсткого кодування значень у DLL!
MonkeyMagix

0

Чому б не використовувати:

  • [ProjectNamespace].Properties.Settings.Default.[KeyProperty] для C #
  • My.Settings.[KeyProperty] для VB.NET

Вам просто потрібно оновити ці властивості під час проектування через:

[Solution Project]->Properties->Settings


Це автоматично створить конфігураційний файл для dll. Але ви не можете читати змінені значення з конфігураційного файлу під час виконання. Нарешті він покаже значення вашої заявки на виклик. Дивіться також відповідь @Joe
Код Папи

Ні, якщо він налаштований для конфігурації користувача. Ідея полягає в тому, щоб відредагувати те, що потрібно користувачеві, налаштувати їх під час виконання, а потім зберегти. Потім, коли користувач працює з бібліотекою, він завантажує його конфігурацію, збережену у відповідному шляху користувача, але працює лише для нього.
Педро Мора

0

використання з конфігурацій повинно бути дуже простим, як це:

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

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

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

Детальніше див. у MiniConfig

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.