2009-02-27 4 views
171

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

Согласно MusicGenesis в 'Putting configuration information in a DLL', это не должно быть проблемой. Так, очевидно, что я делаю что-то неправильно ...

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

return ConfigurationManager.AppSettings["ConnectionString"]; 

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

Любые идеи?

+0

Согласно указанному сообщению: если имя dll было MyDll.dll, тогда файл конфигурации должен быть MyDLL.dll.config. Итак, если вы читаете настройки конфигурации из DLL, она должна правильно ссылаться на свою собственную конфигурацию? – MegaByte

+10

Не имеет значения, какой код запрашивает - он ищет файл, указанный для параметра AppDomain: AppDomain.CurrentDomain.SetupInformation.ConfigurationFile –

+0

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

ответ

13

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

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

var config = ConfigurationManager.OpenExeConfiguration("foo.dll"); 
config.ConnectionStrings. [etc] 
+0

Согласно указанному сообщению: если имя dll было MyDll.dll, тогда файл конфигурации должен быть MyDLL.dll.config , Итак, если вы читаете настройки конфигурации из DLL, она должна правильно ссылаться на свою собственную конфигурацию? – MegaByte

+0

Нет ... Я так не думаю. «с dll» не имеет никаких шансов; по умолчанию он ищет конфигурационный файл, определенный для AppDomain: my.exe.config –

+1

В частности, параметр AppDomain.CurrentDomain.SetupInformation.ConfigurationFile. –

12

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

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

1

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

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

256

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

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

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

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

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

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

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

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

+0

Я думаю, что механизм синхронизации должен быть «именованным событием» и т. Д., Потому что это сквозные процессы – Jacob

+7

:/ Meh. Ours - это приложение для монстров с основным .exe, написанное ребятами в другом часовом поясе, и модули, представленные различными DLL, и динамически связанные через пользовательскую структуру плагина. Все это «вам нужно будет обеспечить, чтобы несколько приложений могли одновременно использовать вашу DLL». Помповость совершенно неверна. – JohnL4

+0

Кроме того, в большой части моей карьеры я видел, что эти прекрасные общие механизмы общих объектов полностью игнорируются, а команды создают библиотеки DLL (или JAR), которые могут использоваться только в одном контексте (и должны присутствовать, или в приложении терпит неудачу). Они также могут быть статически связаны, но это пассе. – JohnL4

3

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

Кенни Льет

85

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

var appConfig = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location); 
string dllConfigData = appConfig.AppSettings.Settings["dllConfigData"].Value; 
+0

В управляемом C++ для VS 2008 System :: Configuration :: Configuration^appConfig = ConfigurationManager :: OpenExeConfiguration (Монтаж :: GetExecutingAssembly() -> Location); \t \t \t \t \t String^name = appConfig-> AppSettings-> Настройки ["name"] -> Value; – Hans

5

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

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

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

+0

Я также использую этот подход, и я доволен тем, как он был разработан до сих пор. – Dave

2

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

var appConfig = ConfigurationManager.OpenExeConfiguration(
    Path.Combine(Environment.CurrentDirectory, Assembly.GetExecutingAssembly().ManifestModule.Name)); 
+0

Спасибо, это сработало для меня. –

2

Я нашел то, что кажется хорошим решением этой проблемы. Я использую 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

17

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

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

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

Изгиб «AppDomain.CurrentDomain.SetupInformation.ConfigurationFile» невозможен, потому что он необходим для обычного поведения app.config.

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

  • NO ручной копия чего-либо от 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 и считывает информацию о разделе в частном поле. После этого я переопределил это [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 в выходной каталог приложения. Возможно, кому-то это будет полезно.

2

Если вы используете библиотеки, которые выглядят на большое количество configation за кадром, таких как WCF, вы могли бы рассмотреть это сделать:

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

Или в PowerShell:

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

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

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

0

В этой статье аналогичная проблема была обсуждена и решить мою проблему How to load a separate Application Settings file dynamically and merge with current settings? может быть helpfu

+0

Хотя это может теоретически ответить на вопрос, [было бы предпочтительнее] (http://meta.stackexchange.com/q/8259) включить сюда основные части ответа и предоставить ссылку для справки. – Adi

3

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

0

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

Это объясняется в here

0

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

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

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

1) Создайте файл конфигурации приложения и назовите его «yourDllName.dll.config»
2) Щелкните правой кнопкой мыши на файле конфигурации, созданном выше, в VS Solution Explorer, щелкните свойства
--- установите «Build Action» = Содержимое
--- установите «Копировать на выход Di» приходской»= Всегда
3) Добавить раздел AppSettings в файл конфигурации (yourDllName.dll.config) с yourKeyName и yourKeyValue

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

4) Добавить систему.Конфигурация для вашей DLL/класса/проекта ссылки
5) Добавьте используя операторы в коде, где вы собираетесь открыть настройки

using System.Configuration; 
using System.Reflection; 

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

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

7 конфиг) rejoice, it works

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

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

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

Смежные вопросы