Эквивалент «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.

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

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

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

PawanS
источник
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 есть хорошая статья о них.

madd0
источник
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");
Firegarden
источник
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");
krlzlx
источник
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.

ghostJago
источник
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

Рахмат Анджираби
источник