Файл конфигурации C # DLL

Я пытаюсь добавить файл app.config в свою DLL, но все попытки потерпели неудачу.

Согласно MusicGenesis в «Помещении информации о конфигурации в DLL» этого не должно быть проблема. Так что очевидно я что-то делаю не так ...

Следующий код должен вернуть мою ConnectionString из моей DLL:

return ConfigurationManager.AppSettings["ConnectionString"];

Однако когда я копирую файл app.config в свое консольное приложение, он работает нормально.

Любые идеи?


person MegaByte    schedule 27.02.2009    source источник
comment
Согласно упомянутому сообщению: если имя dll было MyDll.dll, то файл конфигурации должен быть MyDLL.dll.config. Итак, если вы читаете настройки конфигурации из библиотеки dll, она должна ссылаться на собственную конфигурацию, верно?   -  person MegaByte    schedule 27.02.2009
comment
Неважно, какой код запрашивает - он ищет файл, указанный для параметра AppDomain: AppDomain.CurrentDomain.SetupInformation.ConfigurationFile.   -  person Marc Gravell    schedule 27.02.2009
comment
Примечание. Размещение информации о конфигурации в библиотеке DLL связано с разделением кода конфигурации вашего приложения в библиотеке, чтобы он был отделен от основного кода приложения. Это сильно отличается от отдельного файла конфигурации, специально предназначенного для отдельной библиотеки DLL.   -  person Chris Ammerman    schedule 18.06.2009
comment
см. этот пост [введите здесь описание ссылки] [1], было решением для меня [1]: stackoverflow.com/questions/2389290/   -  person dhailis    schedule 20.11.2011
comment
см. этот пост [Как динамически загрузить отдельный файл настроек приложения и объединить его с текущими настройками?] [1] может оказаться полезным [1]:   -  person dhailis    schedule 20.11.2011


Ответы (17)


Создать файл конфигурации .NET для .DLL нетривиально, и на то есть веские причины. Механизм конфигурации .NET имеет множество встроенных функций, которые упрощают обновление / обновление приложения и защищают установленные приложения от перехвата файлов конфигурации друг друга.

Существует большая разница между тем, как используется DLL, и тем, как используется приложение. Маловероятно, что на одном компьютере будет установлено несколько копий приложения для одного и того же пользователя. Но у вас вполне может быть 100 различных приложений или библиотек, использующих некоторую .NET DLL.

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

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

Из-за всего этого процедура создания файла конфигурации для конкретной библиотеки не так удобна. Это тот же процесс, который вы использовали бы для создания произвольного переносимого файла конфигурации, не привязанного к какой-либо конкретной сборке, но для которого вы хотите использовать XML-схему .NET, раздел конфигурации и механизмы элементов конфигурации и т. Д. Это влечет за собой создание ExeConfigurationFileMap объект, загружая данные, чтобы определить, где будет храниться файл конфигурации, а затем вызывая _2 _._ 3_, чтобы открыть его в новом Configuration экземпляре. Это отключит вас от защиты версий, обеспечиваемой механизмом автоматического создания пути.

По статистике, вы, вероятно, используете эту библиотеку в домашних условиях, и маловероятно, что у вас будет несколько приложений, использующих ее на одном компьютере / пользователе. Но если нет, вам следует помнить об этом. Если вы используете один глобальный файл конфигурации для своей DLL, независимо от приложения, которое на него ссылается, вам нужно беспокоиться о конфликтах доступа. Если два приложения, ссылающиеся на вашу библиотеку, выполняются одновременно, каждое со своим собственным Configuration объектом, то при сохранении изменений в одном из них возникнет исключение, когда вы в следующий раз попытаетесь получить или сохранить данные в другом приложении.

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

Если вы уверены, что хотите иметь глобальные настройки для своей библиотеки DLL независимо от того, где на нее ссылаются, вам нужно будет определить свое местоположение для нее, а не .NET, который автоматически определит подходящий. Вам также необходимо агрессивно управлять доступом к файлу. Вам нужно будет кэшировать как можно больше, сохраняя экземпляр Configuration ТОЛЬКО на время загрузки или сохранения, открывая непосредственно перед и удаляя сразу после. И, наконец, вам понадобится механизм блокировки для защиты файла во время его редактирования одним из приложений, использующих библиотеку.

person Chris Ammerman    schedule 17.06.2009
comment
Я думаю, что механизм синхронизации должен быть именованным событием и т. д., потому что он межпроцессный - person Jacob; 15.11.2012
comment
: / Meh. Наше корпоративное приложение-монстр с основным .exe, написанным парнями в другом часовом поясе, и модулями, представленными различными библиотеками DLL и динамически связанными через настраиваемую структуру плагинов. Все это вам нужно для того, чтобы несколько приложений могли использовать вашу DLL одновременно, напыщенность совершенно неверна. - person JohnL4; 21.06.2013
comment
Более того, на протяжении большей части своей карьеры я видел, как эти прекрасные универсальные механизмы общих объектов полностью игнорировались, когда команды создавали библиотеки DLL (или JAR), которые могут использоваться только в одном контексте (и должны присутствовать, иначе приложение выйдет из строя. ). С таким же успехом они могут быть статически связаны, но это устарело. - person JohnL4; 21.06.2013
comment
если вы уверены, что хотите иметь глобальные настройки для своей DLL независимо от того, где на нее ссылаются ‹, или вы можете добавить ее в файл web.config в соответствующей папке фреймворка [windows] \ Microsoft.NET \ Framework [версия] \ config . - person Phil Cooper; 02.07.2013
comment
@ JohnL4, ты ведь троллишь? Крис имеет в виду файлы dll.config, а не сами файлы dll. Надеюсь, никто не воспринимает эти комментарии всерьез -_- - person user1567453; 06.10.2015
comment
По статистике, вы, вероятно, используете эту библиотеку в домашних условиях, и маловероятно, что у вас будет несколько приложений, использующих ее на одном компьютере / пользователе. Разница между теорией и практикой иногда меня очень раздражает. - person JohnL4; 13.10.2015
comment
К чему относится это предложение? Это отключит вас от защиты версий, обеспечиваемой механизмом автоматического создания пути. - person Panzercrisis; 14.04.2016
comment
@Panzercrisis, функция Visual Studio Settings.settings автоматически создает пути, зависящие от версии, для всех пользовательских настроек. См .: stackoverflow.com/questions/35778528/ - person Deantwo; 23.01.2018

если вы хотите читать настройки из файла конфигурации DLL, но не из корневых приложений web.config или app.config, используйте приведенный ниже код для чтения конфигурации в dll.

var appConfig = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
string dllConfigData = appConfig.AppSettings.Settings["dllConfigData"].Value;
person Morbia    schedule 16.02.2010
comment
В управляемом C ++ для VS 2008 System :: Configuration :: Configuration ^ appConfig = ConfigurationManager :: OpenExeConfiguration (Assembly :: GetExecutingAssembly () - ›Местоположение); Строка ^ name = appConfig- ›AppSettings-› Настройки [имя] - ›Значение; - person Hans; 02.01.2016
comment
Спасибо, это действительно решило мою проблему. Я занимаюсь этой проблемой около двух дней, и до сих пор не заставил ее работать. При отладке теста ConfigurationManager читал из machine.config -Я думаю-, поскольку вытащенные строки подключения относились к SQLExpress - строке подключения, которую я не перечислил-. - person yopez83; 26.01.2019

У меня была та же проблема, и я искал в Интернете несколько часов, но я не смог найти никакого решения, поэтому я сделал свое. Мне было интересно, почему система конфигурации .net такая негибкая.

Справочная информация: я хочу, чтобы у моего DAL.dll был собственный файл конфигурации для базы данных и настроек DAL. Мне также нужен app.config для Enterprise Library и его собственные конфигурации. Поэтому мне нужны и app.config, и dll.config.

Чего я не хотел делать, так это передавать каждое свойство / настройку из приложения на мой слой DAL!

согнуть "AppDomain.CurrentDomain.SetupInformation.ConfigurationFile" невозможно, потому что он мне нужен для нормального поведения app.config.

Мои требования / точки зрения были:

  • НИКАКОГО ручного копирования чего-либо из ClassLibrary1.dll.config в WindowsFormsApplication1.exe.config, потому что это невоспроизводимо для других разработчиков.
  • сохранить использование строгой типизации "Properties.Settings.Default.NameOfValue" (поведение настроек), потому что я думаю, что это основная функция, и я не хотел ее терять
  • Я обнаружил отсутствие ApplicationSettingsBase для внедрения вашего собственного / настраиваемого файла конфигурации или управления (все необходимые поля являются частными в этих классах)
  • использование перенаправления файла "configSource" невозможно, потому что нам пришлось бы скопировать / переписать ClassLibrary1.dll.config и предоставить несколько файлов XML для нескольких разделов (мне это тоже не понравилось)
  • Мне не нравилось писать свой собственный SettingsProvider для этой простой задачи, как предлагает MSDN, потому что я думал, что это будет слишком много.
  • Мне нужны только разделы applicationSettings и connectionStrings из конфигурационного файла

Я придумал модифицировать файл Settings.cs и реализовал метод, который открывает ClassLibrary1.dll.config и считывает информацию раздела в частном поле. После этого я переопределил «this [string propertyName]», чтобы сгенерированный файл Settings.Desginer.cs вызывал мое новое свойство вместо базового класса. Там настройка считывается из Списка.

Наконец, есть следующий код:

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

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

person Sven    schedule 05.04.2011

Я почти уверен, что при использовании ConfigurationManager он загружает файл конфигурации process / AppDomain (app.config / web.config). Если вы хотите загрузить определенный файл конфигурации, вам нужно будет отдельно запросить этот файл по имени ...

Вы можете попробовать:

var config = ConfigurationManager.OpenExeConfiguration("foo.dll");
config.ConnectionStrings. [etc]
person Marc Gravell    schedule 27.02.2009
comment
Согласно упомянутому сообщению: если имя dll было MyDll.dll, то файл конфигурации должен быть MyDLL.dll.config. Итак, если вы читаете настройки конфигурации из библиотеки dll, она должна ссылаться на собственную конфигурацию, верно? - person MegaByte; 27.02.2009
comment
Нет ... я так не думаю. от с dll не имеет шансов; по умолчанию он просматривает файл конфигурации, определенный для домена приложения: my.exe.config - person Marc Gravell; 27.02.2009
comment
В частности, параметр AppDomain.CurrentDomain.SetupInformation.ConfigurationFile. - person Marc Gravell; 27.02.2009
comment
примечание: я пробовал OpenExeConfiguration, и я тоже не уверен, что он работает. Может просто слить конфиг с app.config? - person Marc Gravell; 27.02.2009
comment
Это можно сделать ... но не с такой же поддержкой и безопасностью, как файл app.config для EXE. Смотрите мой ответ. - person Chris Ammerman; 18.06.2009

ConfigurationManager.AppSettings возвращает настройки, определенные для приложения, а не для конкретной DLL, вы можете получить к ним доступ, но будут возвращены настройки приложения.

Если вы используете DLL из другого приложения, ConnectionString должен быть в app.settings приложения.

person Jorge Córdoba    schedule 27.02.2009

Я знаю, что это поздно для вечеринки, однако я подумал, что поделюсь решением, которое использую для DLL.

Я больше из K.I.S.S. школа мышления, поэтому, когда у меня есть .NET DLL, которая хочет хранить внешние точки данных, которые контролируют, как она работает или куда она идет, и т. д. я просто создаю класс "config", который имеет только общедоступные свойства, в которых хранятся все точки данных это необходимо, и я хотел бы иметь возможность управлять внешней по отношению к DLL, чтобы предотвратить ее перекомпиляцию для внесения изменений. Затем я использую XML-сериализацию .Net для сохранения и загрузки объектного представления класса в файл.

Существует множество способов обработки его чтения и доступа к нему, от синглтона, статического служебного класса до методов расширения и т. Д. Это зависит от того, как структурирована ваша DLL, и какой метод лучше всего подходит для вашей DLL.

person Rodney S. Foley    schedule 22.02.2010
comment
Я тоже использую этот подход и доволен тем, как он работает до сих пор. - person Dave; 22.02.2011

вы правы, вы можете прочитать конфигурационный файл dll. Я боролся с этим в течение дня, пока не обнаружил, что проблема была в моем файле конфигурации. Смотрите мой код ниже. он смог бежать.

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

мой Plugin1.dll.config выглядел так, как показано ниже;

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

Я обнаружил, что в моем файле конфигурации отсутствует тег <appSettings>, поэтому посмотрите вокруг, ваша проблема могла быть другой, но не так уж далека от моей.

person mugume david    schedule 04.04.2013

Полное решение не часто можно найти в одном месте ...

1) Создайте файл конфигурации приложения и назовите его "yourDllName.dll.config".
2) Щелкните правой кнопкой мыши файл конфигурации, созданный выше в VS Solution Explorer, щелкните свойства
--- установите "Build Action" = Content
--- установите "Copy To Output Directory" = Always
3) Добавьте раздел appSettings в файл конфигурации (yourDllName. dll.config) на yourKeyName и yourKeyValue

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

4) Добавьте System.Configuration в ссылки на dll / class / project
5) Добавьте операторы using в свой код, где вы собираетесь получить доступ к настройке конфигурации

using System.Configuration;
using System.Reflection;

6) Чтобы получить доступ к значению

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

7) радуйтесь, работает

IMHO, это следует использовать только при разработке новой dll / библиотеки.

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

Конфигурационный файл оказывается отличным справочником, когда вы добавляете appSettings dll в свое фактическое приложение.

person David C Fuchs    schedule 10.11.2017

Поскольку сборка находится во временном кеше, вы должны объединить путь, чтобы получить конфигурацию dll:

var appConfig = ConfigurationManager.OpenExeConfiguration(
    Path.Combine(Environment.CurrentDirectory, Assembly.GetExecutingAssembly().ManifestModule.Name));
person Lin Song Yang    schedule 26.05.2010
comment
вместо Path.Combine (Environment.CurrentDirectory, Assembly.GetExecutingAssembly (). ManifestModule.Name) вы можете использовать Assembly.GetExecutingAssembly (). Location - person Cadburry; 19.02.2019

Если вы используете библиотеки, которые просматривают большое количество настроек за кулисами, такие как WCF, вы можете подумать о следующем:

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

Или в PowerShell:

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

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

Следующее НЕ РЕКОМЕНДУЕТСЯ:
В качестве технического любопытства вот вариант на эту тему. Вы можете создать статический конструктор внутри одного из классов, размещенных в DLL, и выполнять этот вызов оттуда. Я бы не рекомендовал делать это, кроме как в крайнем случае.

person Paul Williams    schedule 19.06.2011

Похоже, что эти файлы конфигурации действительно сбивают с толку, поскольку их поведение меняется от среды разработки к развертыванию. Очевидно, у DLL может быть свой собственный файл конфигурации, но как только вы скопируете и вставите dll (вместе с их файлом конфигурации) в другое место, все это перестанет работать. Единственное решение - вручную объединить файлы app.config в один файл, который будет использовать только exec. Например, myapp.exe будет иметь файл myapp.exe.config, содержащий все настройки для всех dll, используемых myapp.exe. Я использую VS 2008.

person kenny    schedule 25.09.2009

Я нашел хорошее решение этой проблемы. Я использую VS 2008 C #. Мое решение включает использование разных пространств имен между несколькими файлами конфигурации. Я разместил решение в своем блоге: http://tommiecarter.blogspot.com/2011/02/how-to-access-multiple-config-files-in.html.

Например:

Это пространство имен читает / записывает настройки dll:

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

Это пространство имен читает / записывает настройки exe:

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

В статье упоминаются некоторые предостережения. HTH

person Tommie C.    schedule 09.02.2011

Как говорит Марк, это невозможно (хотя Visual Studio позволяет добавлять файл конфигурации приложения в проект библиотеки классов).

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

person Gerrie Schenck    schedule 27.02.2009

Смущает имитация реального файла конфигурации приложения. Я предлагаю вам свернуть свой собственный, потому что довольно легко проанализировать XML-файл, например, LINQ.

Например, создайте XML-файл MyDll.config, как показано ниже, и скопируйте его вместе с DLL. Чтобы поддерживать его в актуальном состоянии, установите для его свойства в Visual Studio значение «Копировать в выходной каталог».

<?xml version="1.0" encoding="utf-8" ?>
 <configuration>
  <setting key="KeyboardEmulation" value="Off"></setting>
 </configuration>

В своем коде прочтите это так:

    XDocument config = XDocument.Load("MyDll.config");
    var settings = config.Descendants("setting").Select(s => new { Key = s.Attribute("key").Value, Value = s.Attribute("value").Value });
    bool keyboardEmulation = settings.First(s => s.Key == "KeyboardEmulation").Value == "On";
person Gerhard Schmeusser    schedule 31.07.2020

В этом посте обсуждалась аналогичная проблема и решалась моя проблема Как динамически загрузить отдельный файл настроек приложения и объединить его с текущими настройками? может помочь

person dhailis    schedule 20.11.2011
comment
Хотя теоретически это может дать ответ на вопрос, было бы предпочтительнее включить сюда основные части ответа и предоставить ссылку для справки. - person Adi; 06.11.2012

Для dll это не должно зависеть от конфигурации, поскольку конфигурация принадлежит приложению, а не dll.

Это объясняется здесь

person Saravanan    schedule 31.05.2013

вы можете использовать этот код:

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);
    }
}
}
person David Lopes    schedule 19.07.2017