C#DLLconfiguration文件

我试图添加一个app.config文件到我的DLL,但所有的尝试都失败了。

根据MusicGenesis在“ 把configuration信息放在一个DLL中 ”这应该不成问题。 所以显然我做错了什么…

下面的代码应该从我的DLL中返回我的ConnectionString:

return ConfigurationManager.AppSettings["ConnectionString"]; 

但是,当我将app.config文件复制到我的控制台应用程序,它工作正常。

有任何想法吗?

为.DLL创build一个.NETconfiguration文件并不是一件容易的事情,而且是有原因的。 .NETconfiguration机制内置了许多function,以方便升级/更新应用程序,并保护已安装的应用程序免于践踏其他configuration文件。

如何使用DLL和如何使用应用程序有很大的区别。 对于同一用户,您不太可能在同一台计算机上安装多个应用程序的副本。 但是,你可能已经有100个不同的应用程序或库都使用了一些.NET DLL。

尽pipe很less需要在一个用户configuration文件中分别跟踪应用程序的不同副本的设置,但您不希望DLL的所有不同用法彼此共享configuration。 因为这个原因,当你使用“normal”方法检索一个Configuration对象时,你得到的对象绑定到你正在执行的App Domain的configuration,而不是特定的程序集。

应用程序域被绑定到加载了你的代码实际所在的程序集的根程序集。在大多数情况下,这将是你的主.EXE程序集,这是加载.DLL的程序集。 可以在应用程序中启动其他应用程序域,但是必须明确提供有关该应用程序域根组件的信息。

因为这一切,创build特定于库的configuration文件的过程并不方便。 创build一个任意可移植configuration文件的过程与创build一个ExeConfigurationFileMap过程是一样的,不需要绑定到任何特定的程序集,而是使用.NET的XML模式,configuration部分和configuration元素机制等。对象,加载数据来确定configuration文件的存储位置,然后调用ConfigurationManagerOpenMappedExeConfiguration将其打开成一个新的Configuration实例。 这将使您免受自动path生成机制提供的版本保护。

从统计的angular度来说,你可能在内部使用这个库,并且不太可能有多个应用程序在任何一台机器/用户中使用它。 但是,如果没有,你应该记住一些事情。 如果为DLL使用单个全局configuration文件,则无论引用它的应用程序如何,都需要担心访问冲突。 如果两个引用您的库的应用碰巧正在同时运行,每个都有自己的Configuration对象,那么当您保存更改时,下次尝试在另一个应用中检索或保存数据时,将导致exception。

解决这个问题的最安全和最简单的方法是要求加载DLL的程序集也提供一些关于它本身的信息,或者通过检查引用程序集的应用程序域来检测它。 使用它来创build某种文件夹结构,以便为引用您的DLL的每个应用程序保留单独的用户configuration文件。

如果您确定要为您的DLL进行全局设置,无论它在哪里被引用,您都需要确定您的位置,而不是.NET自动找出合适的位置。 您还需要积极主动地pipe理对文件的访问。 您将需要尽可能caching,只要保持Configuration实例,只要它需要加载或保存,立即打开和立即处置。 最后,您需要一个locking机制来保护文件,使其在使用该库的应用程序之一进行编辑。

如果你想从DLL的configuration文件读取设置,而不是从根应用程序web.config或app.config使用下面的代码来读取DLL中的configuration设置。

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

我有同样的问题,并搜查了几个小时的networking,但我找不到任何解决scheme,所以我做了我自己的。 我想知道为什么.netconfiguration系统是如此僵化。

背景:我想让我的DAL.dll拥有自己的数据库和DAL设置的configuration文件。 我还需要为企业库和它自己的configurationapp.config。 所以我需要app.config和dll.config。

我不想做的是从应用程序到我的DAL层传递每个属性/设置!

弯曲“AppDomain.CurrentDomain.SetupInformation.ConfigurationFile”是不可能的,因为我需要它为正常的app.config行为。

我的要求/观点是:

  • 没有任何从ClassLibrary1.dll.config到WindowsFormsApplication1.exe.config的任何手动副本,因为这对于其他开发者来说是不可重复的。
  • 保留使用强types“Properties.Settings.Default.NameOfValue”(设置行为),因为我认为这是一个重要的function,我不想失去它
  • 我发现缺乏ApplicationSettingsBase来注入自己的/自定义的configuration文件或pipe理(所有必要的字段在这些类中是私有的)
  • 使用“configSource”文件redirect是不可能的,因为我们必须复制/重写ClassLibrary1.dll.config并为几个部分提供几个XML文件(我也不喜欢这样)
  • 我不喜欢为MSDNbuild议的这个简单任务编写我自己的SettingsProvider,因为我认为这太简单了
  • 我只需要configuration文件中的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输出目录复制到您的应用程序的输出目录。 也许有人会觉得它有用。

当使用ConfigurationManager时,我很确定它正在加载进程/ AppDomainconfiguration文件(app.config / web.config)。 如果你想加载一个特定的configuration文件,你必须特别要求该文件的名称…

你可以尝试:

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

ConfigurationManager.AppSettings返回为应用程序定义的设置,而不是为特定的DLL,您可以访问它们,但是它将返回的应用程序设置。

如果您使用的是另一个应用程序的dll,那么ConnectionString应该位于应用程序的app.settings中。

我知道这是晚了,但我想我会分享我用于DLL的解决scheme。

我更喜欢KISS的思维方式,所以当我有一个想要存储外部数据点,控制它如何工作或去哪里的.NET DLL的时候,我只需创build一个只有公共属性的“configuration”类它存储所有需要的数据点,我希望能够控制DLL的外部,以防止重新编译它进行更改。 然后我使用.Net的XML序列化来保存和加载类的对象表示到一个文件。

然后有很多方法来处理读取和访问它,从一个单例,一个静态工具类到扩展方法等等。这取决于你的DLL的结构以及哪种方法最适合你的DLL。

看起来像这个configuration文件真的很混乱,澄清他们的行为从开发环境改变到部署。 显然一个DLL可以有自己的configuration文件,但是一旦你复制并粘贴在其​​他地方的DLL(和他们的configuration文件),整个事情停止工作。 唯一的解决办法是手动将app.config文件合并成一个文件,这个文件只能被exec使用。 例如,myapp.exe将有一个myapp.exe.config文件,其中包含myapp.exe使用的所有dll的所有设置。 我正在使用VS 2008。

Kenny Liew

你是正确的,你可以读取一个DLL的configuration文件。 我挣扎着这一天,直到我发现我的configuration文件是问题。 看到我的代码如下。 它能够运行。

  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> 

我发现我的configuration文件缺less<appSettings>标签,所以看看周围,你的问题可能是不同的,但离我的距离不远。

由于程序集驻留在临时caching中,因此您应该组合path以获取dll的configuration:

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

我发现这个问题似乎是一个很好的解决scheme。 我正在使用VS 2008 C#。 我的解决scheme涉及在多个configuration文件之间使用不同的名称空间。 我已经在我的博客上发布了解决scheme: 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

如果您使用的库在幕后查找大量的解决scheme(如WCF),则可以考虑这样做:

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

或者在PowerShell中:

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

海事组织这种技术是一种代码气味,真的只适用于特设脚本。 如果你发现自己想要在生产代码中做到这一点,也许是时候进行架构审查了。

以下是不推荐的:
作为一个技术好奇心,这是一个主题的变化。 您可以在DLL中的一个类中创build一个静态构造函数,并从那里进行调用。 除了作为最后的手段,我不会推荐这样做。

正如Marc所说,这是不可能的(尽pipeVisual Studio允许您在类库项目中添加应用程序configuration文件)。

您可能想查看AssemblySettings类似乎使程序集configuration文件成为可能。

在这篇文章中讨论了一个类似的问题,并解决了我的问题如何dynamic加载一个单独的应用程序设置文件,并与当前设置合并? 可能是帮助

对于一个DLL,它不应该依赖于configuration,因为configuration是由应用程序拥有,而不是由DLL。

这在这里解释

你可以使用这个代码:

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

完整的解决scheme不是经常在一个地方find…

1)创build一个应用程序configuration文件,并将其命名为“yourDllName.dll.config”
2)右键单击上面在VS解决scheme资源pipe理器中创build的configuration文件,单击属性
—设置“构build行动”=内容
—设置“复制到输出目录”=始终
3)使用yourKeyName和yourKeyValue将appSettings节添加到configuration文件(yourDllName.dll.config)

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

4)添加System.Configuration到你的dll / class / project引用
5)添加使用语句到您想要访问configuration设置的代码

 using System.Configuration; using System.Reflection; 

6)访问该值

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

7)欢喜,它的作品

恕我直言,这只能用于开发一个新的DLL /库。

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

configuration文件最终是一个很好的参考,当你将dll的appSettings添加到您的实际应用程序。