Эквивалент «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 - это 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 из моих проектов test & 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 serialize / deserialize по мере необходимости. Вы можете называть это как хотите. Если ваш конфиг "статический" и не нуждается в изменении, вы также можете добавить его в проект в качестве встроенного ресурса.

Надеюсь, что это дает некоторую идею


6
ConfigurationSettingsв настоящее время устарела и заменена на ConfigurationManager, так что эквивалент будет теперьConfigurationManager.AppSettings
Gone Coding

2
голосование против вопрос за dll, а не за приложение. лучшее решение: stackoverflow.com/a/5191101/2935383
raiserle

3
Я подозреваю, что это предложение не сработает в случае библиотек dll с поздним связыванием, которые не будут знать, что их вызывает исполняемый файл.
beanmf

9

Конфигурационные файлы находятся в области приложения, а не в области сборки. Поэтому вам нужно поместить разделы конфигурации вашей библиотеки в файл конфигурации каждого приложения, которое использует вашу библиотеку.

Тем не менее, не рекомендуется получать конфигурацию из файла конфигурации приложения, особенно из appSettingsраздела, в библиотеке классов. Если вашей библиотеке нужны параметры, они, вероятно, должны быть переданы как аргументы метода в конструкторах, фабричных методах и т. Д. Тем, кто вызывает вашу библиотеку. Это предотвращает случайное повторное использование вызывающими приложениями записей конфигурации, ожидаемых библиотекой классов.

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

Вы можете узнать больше о пользовательских разделах конфигурации на MSDN, а также у Phil Haack есть хорошая статья о них.


7
«Не рекомендуется получать конфигурацию из файла конфигурации в библиотеке классов», - я категорически не согласен с этим. Например, библиотека классов DAL должна обычно получать данные конфигурации, такие как строки подключения, из файла конфигурации приложения, а не передавать эту информацию из уровня BLL. Любые классы Framework, которые используют конфигурацию (например, членство в ASP.NET), работают таким образом.
Джо

Я немного изменил свой ответ. Я все еще придерживаюсь того, что я сказал, но вы правы, я никогда не намеревался подразумевать, что файлы конфигурации не должны использоваться вообще. Я имел в виду, что вместо основанных на соглашениях 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 / applicationatioNSettings, а также значения по умолчанию для этих настроек из вашего Settings.settings. файл.

Однако этот файл конфигурации не будет использоваться во время выполнения - вместо этого библиотека классов использует файл конфигурации своего хост-приложения.

Я считаю, что основная причина создания этого файла заключается в том, что вы можете скопировать / вставить настройки в файл конфигурации хост-приложения.


4

В настоящее время я создаю плагины для розничной торговой марки программного обеспечения, которые на самом деле являются библиотеками классов .net. Как требование, каждый плагин должен быть настроен с использованием файла конфигурации. После небольшого исследования и тестирования я собрал следующий класс. Это делает работу без нареканий. Обратите внимание, что я не реализовал локальную обработку исключений в моем случае, потому что я ловлю исключения на более высоком уровне.

Может потребоваться некоторая настройка, чтобы получить правильную десятичную точку, в случае десятичных и двойных чисел, но она отлично работает для моего 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);
    }
}

Пример файла 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
Brilliant! Это помогло мне запустить автоматические тесты Windows Application Driver на целевых машинах. В моем случае dll были из тестового проекта. Единственное, что я хотел бы добавить, это то, что в Win App Driver (и, возможно, других формах автоматического тестирования) BaseDirectory фактически является выходной папкой, которая меняется каждый раз. Мне пришлось подстроку, как это ... AppDomain.CurrentDomain.BaseDirectory.Substring (0, AppDomain.CurrentDomain.BaseDirectory.IndexOf ("TestResults")). таким образом я мог вырезать ненужную папку вывода, так как мой файл конфигурации находился в той же папке, что и мои тестовые библиотеки.
Эван

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 в вашей сборке DLL .NET, xUnit будет читать .config библиотеки во время выполнения. И он будет игнорировать любой файл App.config, добавленный в тестовый или DLL-проект.
Zeek2

1

Используйте добавить существующий элемент, выберите конфигурацию приложения из проекта DLL. Прежде чем нажать кнопку «Добавить», используйте маленькую стрелку «вниз» справа от кнопки «Добавить», чтобы добавить ссылку.

Я делаю это все время в моем dev.


1

Преамбула : я использую NET 2.0;

Решение, опубликованное Яннисом Леуссисом, является приемлемым, но у меня были некоторые проблемы с ним.

Во-первых, 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.