我试图将app.config文件添加到我的DLL中,但所有尝试均失败。
根据MusicGenesis在“ 将配置信息放入DLL ”中所述,这应该不是问题。所以很明显我做错了...
以下代码应从我的DLL返回我的ConnectionString:
return ConfigurationManager.AppSettings["ConnectionString"];
但是,当我将app.config文件复制到控制台应用程序时,它可以正常工作。
有任何想法吗?
我试图将app.config文件添加到我的DLL中,但所有尝试均失败。
根据MusicGenesis在“ 将配置信息放入DLL ”中所述,这应该不是问题。所以很明显我做错了...
以下代码应从我的DLL返回我的ConnectionString:
return ConfigurationManager.AppSettings["ConnectionString"];
但是,当我将app.config文件复制到控制台应用程序时,它可以正常工作。
有任何想法吗?
Answers:
有充分的理由为.DLL创建.NET配置文件并非易事。.NET配置机制具有很多内置功能,以方便对应用程序进行轻松升级/更新,并保护已安装的应用程序免于踩踏彼此的配置文件。
DLL的使用方式与应用程序的使用方式之间存在很大差异。您不太可能在同一台计算机上为同一用户安装多个应用程序副本。但是您很可能拥有100个不同的应用程序或库,它们都利用了某些.NET DLL。
虽然有很少需要单独跟踪设置一个用户配置文件中的应用程序的不同副本,这是非常不可能的,你想全部DLL来共享配置彼此的不同用法。因此,当您使用“常规”方法检索配置对象时,返回的对象将与您在其中执行的App Domain的配置绑定,而不是与特定程序集绑定。
App Domain绑定到根程序集,该根程序集加载了您的代码实际所在的程序集。在大多数情况下,这将是您的主.EXE的程序集,即加载了.DLL的程序集。可以在一个应用程序中启动其他应用程序域,但是您必须明确提供有关该应用程序域的根程序集的信息。
由于所有这些,创建特定于库的配置文件的过程并不那么方便。这与创建不绑定到任何特定程序集的任意可移植配置文件时所使用的过程相同,但是要使用.NET的XML模式,配置节和配置元素机制等,因此需要创建一个ExeConfigurationFileMap
对象。 ,加载数据以标识配置文件的存储位置,然后调用ConfigurationManager
。OpenMappedExeConfiguration
将其打开到新Configuration
实例中。这将使您脱离自动路径生成机制提供的版本保护。
从统计学上讲,您可能是在内部设置中使用此库的,并且不太可能在任何一台机器/用户中都拥有多个使用该库的应用程序。 但是,如果没有,您应该记住一些事情。如果您为DLL使用单个全局配置文件,则无论引用该应用程序是什么,都需要担心访问冲突。如果引用您的库的两个应用程序恰好同时运行,并且每个应用程序都Configuration
打开了自己的对象,那么当其中一个保存更改时,下次您尝试在另一个应用程序中检索或保存数据时,它将导致异常。
解决此问题的最安全,最简单的方法是要求正在加载DLL的程序集还提供有关其自身的某些信息,或者通过检查引用程序集的App Domain进行检测。使用此方法创建某种文件夹结构,以为引用DLL的每个应用程序保留单独的用户配置文件。
如果确定无论在何处引用DLL,都希望对其进行全局设置,则需要确定其位置,而不是.NET自动确定合适的位置。您还需要积极主动地管理对文件的访问。您将需要尽可能多地缓存,Configuration
仅在加载或保存实例之前就将其保持在附近,并在此之前立即打开并在之后立即进行处置。最后,您需要一种锁定机制来保护文件,而该文件正在由使用该库的一个应用程序进行编辑时。
如果要从DLL的配置文件中读取设置,而不是从根应用程序web.config或app.config中读取设置,请使用以下代码读取dll中的配置。
var appConfig = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
string dllConfigData = appConfig.AppSettings.Settings["dllConfigData"].Value;
我遇到了同样的问题,并在网上搜索了几个小时,但找不到任何解决方案,因此我自己制定了解决方案。我想知道为什么.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调用了我的新Property而不是基类。在那里从列表中读出设置。
最后有以下代码:
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时,我很确定它正在加载进程/ AppDomain
配置文件(app.config / web.config)。如果要加载特定的配置文件,则必须按名称专门要求该文件...
您可以尝试:
var config = ConfigurationManager.OpenExeConfiguration("foo.dll");
config.ConnectionStrings. [etc]
没错,您可以读取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>
标记,因此环顾四周,您的问题可能有所不同,但与我的相距不远。
由于程序集驻留在临时缓存中,因此您应该组合路径以获取dll的配置:
var appConfig = ConfigurationManager.OpenExeConfiguration(
Path.Combine(Environment.CurrentDirectory, Assembly.GetExecutingAssembly().ManifestModule.Name));
如果您正在使用在后台查找大量配置的库(例如WCF),则可以考虑这样做:
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "MyWcfClientWrapper.dll.config");
或在PowerShell中:
[AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", "MyWcfClientWrapper.dll.config")
IMO这项技术是一种代码气味,实际上仅适用于临时脚本。如果您发现自己想在生产代码中执行此操作,那么也许是时候进行体系结构审查了。
不建议以下内容:
由于技术上的好奇,这里是主题的变体。您可以在DLL所包含的类之一中创建一个静态构造函数,然后从那里进行此调用。除非万不得已,否则我不建议您这样做。
完整的解决方案经常不在一个地方找到...
1)创建一个应用程序配置文件并将其命名为“ yourDllName.dll.config”
2)右键单击在VS Solution Explorer中上面创建的配置文件,单击属性
-设置“构建操作” =内容
---设置“复制到输出目录” =始终
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引用中
5)将using语句添加到您打算访问config设置的代码中
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添加到实际应用程序时,该配置文件最终是一个很好的参考。
我发现似乎可以很好地解决此问题。我正在使用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;
文章中提到了一些警告。高温超导
正如Marc所说,这是不可能的(尽管Visual Studio允许您在类库项目中添加应用程序配置文件)。
您可能想检出AssemblySettings类,该类似乎使程序集配置文件成为可能。
在这篇文章中,讨论了类似的问题并解决了我的问题。如何动态加载单独的“应用程序设置”文件并与当前设置合并?可能是帮助
您可以使用以下代码:
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);
}
}
}