C# DLL 配置文件

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

根据“将配置信息放入DLL中”中的MusicGenesis,这应该不是问题。所以很明显我做错了什么…

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

return ConfigurationManager.AppSettings["ConnectionString"];

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

什么好主意吗?

245830 次浏览

当使用ConfigurationManager时,我非常确定它正在加载进程/AppDomain配置文件(app.config / web.config)。如果你想要加载一个特定的配置文件,你必须通过文件名来明确地请求该文件…

你可以试试:

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

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

如果你从其他应用程序中使用你的dll,那么ConnectionString应该在应用程序的app.settings中。

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

你可能想要查看AssemblySettings类,它似乎使程序集配置文件成为可能。

为. dll创建. net配置文件并不简单,这是有原因的。. net配置机制有很多内置的特性,可以方便地升级/更新应用程序,并保护已安装的应用程序不破坏彼此的配置文件。

如何使用DLL和如何使用应用程序之间有很大的区别。您不太可能在同一台机器上为同一用户安装多个应用程序副本。但是你可能有100个不同的应用程序或库都在使用一些。net DLL。

虽然很少需要在一个用户配置文件中分别跟踪应用程序的不同副本的设置,但非常不太可能希望DLL的所有不同用法彼此共享配置。因此,当你使用“normal”方法检索Configuration对象时,你得到的对象绑定到你正在执行的App Domain的配置,而不是特定的程序集。

应用程序域绑定到根程序集,该程序集加载了你的代码所在的程序集。在大多数情况下,这将是你的主. exe的程序集,它加载了. dll。可以在应用程序中启动其他应用程序域,但必须显式提供关于该应用程序域的根程序集的信息。

因此,创建特定于库的配置文件的过程就不那么方便了。这与您创建任意可移植配置文件的过程是相同的,该配置文件不绑定到任何特定的程序集,但您希望为此使用. net的XML模式、配置节和配置元素机制等。这需要创建一个ExeConfigurationFileMap对象,加载数据以确定配置文件将存储在哪里,然后调用ConfigurationManager。将其打开到一个新的Configuration实例中。这个切断了自动路径生成机制提供的版本保护。

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

解决这个问题最安全、最简单的方法是要求加载DLL的程序集也提供一些关于自身的信息,或者通过检查引用程序集的App Domain来检测它。使用它来创建某种文件夹结构,为每个引用DLL的应用程序保存单独的用户配置文件。

如果你是某些,你想对你的DLL有全局设置,不管它在哪里被引用,你需要确定它的位置,而不是。net自动找到一个合适的。您还需要积极地管理对文件的访问。你需要尽可能多地缓存,只在加载或保存时保留Configuration实例,在加载或保存前立即打开,在加载或保存后立即释放。最后,你需要一个锁机制来保护文件,当它被使用库的应用程序编辑时。

看起来这个配置文件真的很混乱,因为它们的行为从开发环境到部署环境都发生了变化。显然,DLL可以有自己的配置文件,但一旦你复制并粘贴DLL(连同它们的配置文件)到其他地方,整个事情就停止工作了。 唯一的解决方案是手动将app.config文件合并为一个文件,该文件仅供exec使用。例如,myapp.exe将有一个myapp.exe.config文件,其中包含myapp.exe使用的所有dll的所有设置。 我用的是vs2008。< / p >

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

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

我知道这有点晚了,但是我想分享一下我用于DLL的解决方案。

我更倾向于采用K.I.S.S.的思维方式,所以当我有一个。net DLL想要存储外部数据点时,这些数据点可以控制它的工作方式或去向等等。我只是创建了一个“配置”类,它只有存储它所需的所有数据点的公共属性,并且我希望能够在DLL外部进行控制,以防止重新编译它来进行更改。然后我使用. net的XML Serializing来保存类的对象表示并将其加载到一个文件中。

有很多方法来读取和访问它,从单例、静态实用程序类到扩展方法等等。这取决于DLL的结构方式以及最适合DLL的方法。

由于程序集驻留在临时缓存中,您应该结合路径来获得dll的配置:

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

我找到了一个解决这个问题的好办法。我使用的是vs2008 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

我也遇到了同样的问题,在网上搜索了几个小时,但我找不到任何解决方案,所以我自己做了一个。我想知道为什么。net配置系统如此不灵活。

背景:我想有我的DAL.dll有自己的配置文件数据库和DAL设置。我还需要企业库的app.config及其自己的配置。所以我需要app.config和dll.config。

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

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

我的要求/观点是:

  • 没有从ClassLibrary1.dll中手动拷贝任何东西。config到WindowsFormsApplication1.exe。配置,因为这对于其他开发人员是不可复制的。
  • 保留强类型“Properties.Settings.Default. properties”的用法。NameOfValue”(设置行为)因为我认为这是一个主要功能,我不想失去它
  • 我发现缺少ApplicationSettingsBase来注入你自己的/自定义配置文件或管理(所有必要的字段在这些类中都是私有的)
  • 使用“configSource”文件重定向是不可能的,因为我们必须复制/重写ClassLibrary1.dll。配置并为几个部分提供几个XML文件(我也不喜欢这样)
  • 我不喜欢像MSDN建议的那样为这个简单的任务编写我自己的SettingsProvider,因为我认为那太简单了
  • 我只需要配置文件中的部分applicationSettings和connectionStrings

我提出修改Settings.cs文件,并实现了一个打开ClassLibrary1.dll的方法。配置并读取私有字段中的节信息。之后,我重写了“this[string propertyName]”,所以生成的settings . designer .cs调用我的新属性,而不是基类。在那里,设置被从List中读出。

最后是下面的代码:

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。配置从ClassLibrary1输出目录到应用程序的输出目录。 也许有人会觉得它有用。< / p >

如果你正在使用库来查找大量的幕后配置,比如WCF,你可以考虑这样做:

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

或者在PowerShell中:

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

在我看来,这种技术是一种代码气味,实际上只适合在临时脚本中使用。如果您发现自己想在产品代码中这样做,也许是时候进行架构审查了。

< p > 不建议:
出于技术上的好奇,这里有一个关于这个主题的变体。您可以在DLL中的一个类中创建一个静态构造函数,并从那里进行此调用。我不建议这样做,除非是万不得已。< / p >

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

您是正确的,您可以读取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>标签,所以环顾四周,你的问题可能有所不同,但与我的没有那么远。

对于一个dll,它不应该依赖于配置,因为配置是由应用程序而不是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);
}
}
}
完整的解决方案通常不会在一个地方找到…< br > < br > 1)创建一个应用配置文件,并将其命名为“yourDllName.dll.config”
2)在VS解决方案资源管理器中右键单击上面创建的配置文件,单击properties
——set "Build Action" = Content
——set "Copy To Output Directory" = Always
3)在配置文件(yourDllName.dll.config)中添加一个appSettings部分,其中包含你的keyname和keyvalue

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

4)添加系统。配置到您的dll/类/项目引用
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添加到实际应用程序中时,配置文件最终会成为一个很好的参考。

嘲笑一个“真实”的人是令人困惑的。应用程序配置文件。我建议您自己编写,因为使用LINQ等工具解析XML文件非常容易。

例如创建一个XML文件MyDll。配置如下,并复制它与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";