我正在尝试将app.config文件添加到我的DLL中,但所有尝试都失败了。
根据MusicGenesis的'Putting configuration information in a DLL',这应该不是问题。显然我做错了......
以下代码应该从我的DLL返回我的ConnectionString:
return ConfigurationManager.AppSettings["ConnectionString"];
但是,当我将app.config文件复制到我的控制台应用程序时,它可以正常工作。
有什么想法吗?
答案 0 :(得分:270)
为.DLL创建.NET配置文件并非易事,这是有充分理由的。 .NET配置机制内置了许多功能,以便于轻松升级/更新应用程序,并保护已安装的应用程序免受其他配置文件的侵扰。
使用DLL的方式与应用程序的使用方式之间存在很大差异。您不可能在同一台计算机上为同一用户安装多个应用程序副本。但是你可能有100个不同的应用程序或库都使用了一些.NET DLL。
虽然很少需要在一个用户配置文件中分别跟踪应用程序的不同副本的设置,但非常不太可能您希望DLL的所有不同用法与彼此。因此,当您使用“普通”方法检索Configuration对象时,您获取的对象与您正在执行的App Domain的配置相关联,而不是特定的程序集。
App Domain绑定到根组件,该组件加载了代码实际所在的程序集。在大多数情况下,这将是主.EXE的程序集,这是加载.DLL的内容。可以在应用程序中启动其他应用程序域,但您必须明确提供有关该应用程序域的根程序集的信息。
由于这一切,创建特定于库的配置文件的过程不太方便。这与用于创建任何特定程序集的任意可移植配置文件的过程相同,但是您要使用.NET的XML模式,配置节和配置元素机制等。这需要创建一个{ {1}}对象,加载数据以标识配置文件的存储位置,然后调用ExeConfigurationFileMap
。ConfigurationManager
将其打开到新的OpenMappedExeConfiguration
实例中。 将使您免受自动路径生成机制提供的版本保护。
从统计学上讲,您可能在内部设置中使用此库,并且您不可能在任何一台计算机/用户中使用多个应用程序。 但如果没有,你应该记住一些事情。如果对DLL使用单个全局配置文件,则无论引用它的应用程序如何,都需要担心访问冲突。如果引用您的库的两个应用程序恰好同时运行,每个应用程序都打开了自己的Configuration
对象,那么当一个应用程序保存更改时,下次尝试检索或保存其他数据时会导致异常应用
解决此问题的最安全和最简单的方法是要求加载DLL的程序集也提供有关自身的一些信息,或者通过检查引用程序集的App Domain来检测它。使用它来创建某种文件夹结构,以便为引用DLL的每个应用程序保留单独的用户配置文件。
如果你确定,你想要为你的DLL设置全局设置,无论它在哪里被引用,你都需要确定它的位置,而不是.NET自动确定一个合适的DLL。 。您还需要积极管理对文件的访问。您需要尽可能地缓存,只要保持Configuration
实例,只要加载或保存,在之前立即打开并在之后立即处置。最后,在使用该库的其中一个应用程序编辑文件时,您需要一个锁定机制来保护该文件。
答案 1 :(得分:97)
如果你想从DLL的配置文件中读取设置,而不是从根应用程序web.config或app.config中读取设置,请使用下面的代码来读取dll中的配置。
var appConfig = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
string dllConfigData = appConfig.AppSettings.Settings["dllConfigData"].Value;
答案 2 :(得分:19)
我遇到了同样的问题并在网上搜索了几个小时,但我找不到任何解决方案,所以我自己做了。我想知道为什么.net配置系统如此不灵活。
背景:我想让我的DAL.dll拥有自己的数据库和DAL设置配置文件。我还需要企业库的app.config及其自己的配置。所以我需要app.config和dll.config。
我不想做的是将每个属性/设置从应用程序传递到我的DAL层!
无法弯曲“AppDomain.CurrentDomain.SetupInformation.ConfigurationFile”,因为我需要正常的app.config行为。
我的要求/观点是:
我想出了修改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输出目录复制到应用程序的输出目录即可。 也许有人会发现它很有用。
答案 3 :(得分:14)
使用ConfigurationManager时,我很确定它正在加载进程/ AppDomain
配置文件(app.config / web.config)。如果要加载特定的配置文件,则必须按名称专门请求该文件...
你可以尝试:
var config = ConfigurationManager.OpenExeConfiguration("foo.dll");
config.ConnectionStrings. [etc]
答案 4 :(得分:13)
ConfigurationManager.AppSettings返回为应用程序定义的设置,而不是特定的DLL,您可以访问它们,但它是将返回的应用程序设置。
如果您在其他应用程序中使用dll,则ConnectionString应位于应用程序的app.settings中。
答案 5 :(得分:5)
我知道派对迟到了,但我想我会分享我用于DLL的解决方案。
我更像是K.I.S.S.思考,所以当我有一个.NET DLL想要存储外部数据点来控制它的工作方式或它去的地方等等。我只是创建一个“config”类,它只有存储所有数据点的公共属性它需要并且我希望能够控制DLL的外部以防止重新编译它以进行更改。然后我使用.Net的XML Serializing来保存并将类的对象表示加载到文件中。
有很多方法可以处理读取和访问它,从Singleton,静态实用程序类到扩展方法等。这取决于你的DLL的结构以及最适合你的DLL的方法。
答案 6 :(得分:4)
你是对的,你可以读取一个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>
标记,所以环顾四周,您的问题可能会有所不同,但距离我的版本不远。
答案 7 :(得分:3)
看起来这样的配置文件真的令人困惑,因为他们的行为从开发环境变为部署。显然一个DLL可以拥有自己的配置文件,但是一旦你将dll(连同它们的配置文件)复制并粘贴到别处,整个事情就停止了。 唯一的解决方案是手动将app.config文件合并到一个文件中,该文件只能由exec使用。对于例如myapp.exe将有一个myapp.exe.config文件,其中包含myapp.exe使用的所有dll的所有设置。 我正在使用VS 2008.
答案 8 :(得分:3)
由于程序集驻留在临时缓存中,您应该组合路径以获取dll的配置:
var appConfig = ConfigurationManager.OpenExeConfiguration(
Path.Combine(Environment.CurrentDirectory, Assembly.GetExecutingAssembly().ManifestModule.Name));
答案 9 :(得分:3)
如果您正在使用能够在幕后查找大量协作的库(例如WCF),您可以考虑这样做:
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "MyWcfClientWrapper.dll.config");
或者在PowerShell中:
[AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", "MyWcfClientWrapper.dll.config")
IMO这种技术是一种代码气味,实际上只适用于临时脚本。如果您发现自己想要在生产代码中执行此操作,可能是时候进行架构审查了。
建议不要使用以下内容:
作为一种技术好奇心,这里有一个主题的变化。您可以在DLL中的一个类中创建静态构造函数,并从那里进行此调用。除非作为最后的手段,否则我不建议这样做。
答案 10 :(得分: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
答案 11 :(得分:1)
正如Marc所说,这是不可能的(尽管Visual Studio允许您在类库项目中添加应用程序配置文件)。
您可能想查看似乎可以使汇编配置文件成为可能的AssemblySettings类。
答案 12 :(得分:1)
在一个地方经常找不到完整的解决方案......
1)创建一个app配置文件并将其命名为“yourDllName.dll.config”
2)右键单击VS解决方案资源管理器中创建的配置文件,单击属性
---设置“构建操作”=内容
---设置“复制到输出目录”=始终
3)使用yourKeyName和yourKeyValue添加appSettings部分到配置文件(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 references
中
5)将using语句添加到您打算访问配置设置的代码中
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
当您将dll的appSettings添加到实际应用程序时,配置文件最终成为一个很好的参考。
答案 13 :(得分:1)
模拟“真实的”应用程序配置文件会令人困惑。我建议您自己动手,因为使用以下方法解析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";
答案 14 :(得分:0)
在这篇文章中讨论了类似的问题并解决了我的问题How to load a separate Application Settings file dynamically and merge with current settings?可能是帮助
答案 15 :(得分:0)
对于dll,它不应该依赖于配置,因为配置由应用程序而不是dll拥有。
解释了这一点答案 16 :(得分:0)
您可以使用此代码:
String