C # DLL файл конфигурации - PullRequest
       112

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

183 голосов
/ 27 февраля 2009

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

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

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

return ConfigurationManager.AppSettings["ConnectionString"];

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

Есть идеи?

Ответы [ 16 ]

270 голосов
/ 17 июня 2009

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

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

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

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

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

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

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

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

97 голосов
/ 16 февраля 2010

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

var appConfig = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
string dllConfigData = appConfig.AppSettings.Settings["dllConfigData"].Value;
19 голосов
/ 05 апреля 2011

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

14 голосов
/ 27 февраля 2009

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

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

var config = ConfigurationManager.OpenExeConfiguration("foo.dll");
config.ConnectionStrings. [etc]
13 голосов
/ 27 февраля 2009

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

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

5 голосов
/ 22 февраля 2010

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

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

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

4 голосов
/ 04 апреля 2013

Вы правы, вы можете прочитать файл конфигурации 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);

my 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>, так что оглянись, твоя проблема могла отличаться, но не так далеко от моей.

3 голосов
/ 20 июня 2011

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

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

Или в PowerShell:

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

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

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

3 голосов
/ 26 мая 2010

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

var appConfig = ConfigurationManager.OpenExeConfiguration(
    Path.Combine(Environment.CurrentDirectory, Assembly.GetExecutingAssembly().ManifestModule.Name));
3 голосов
/ 25 сентября 2009

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

...