DLL 的 App.Config
在您的 DLL 中使用 app.config。
引言
当为分发开发 DLL 时,通常希望有一个与该 DLL 关联的 app.config 文件。但是,.NET 1.1 框架只允许一个 app.config 文件,并且它通常与正在运行的应用程序关联。这确实让开发人员陷入困境,因为他们不知道应用程序是使用 app.config 来“合并”其条目,还是需要应用程序开发人员在其配置文件中包含用于 DLL 使用的条目。
背景
一种常用的方法是编写您自己的 XML 文件并将您的配置信息放在那里。这种方法有几个缺点。如果您包含了一个第三方 DLL,它具有期望在 app.config 文件中看到的配置信息怎么办?您现在陷入了同样的问题。当您在 DLL 中使用 Microsoft Enterprise Library 时,就会出现这种情况。库的配置工具在 app.config 文件中添加一行,指向其自己的配置文件以供内部使用。当您调用库类时,它会在 app.config 文件中查找其自己的配置文件的名称。从这里开始,事情变得一团糟。
如果您尝试在 Google 上找到此问题的答案,您会发现“无法完成”。本文将解释如何完成它。
我想先声明以下免责声明:使用反射“修补”回另一个类不是一个常见的做法。这个例子是一个极端的例子,以解决我认为是 .NET 框架中一个严重的缺陷。在开发这项技术时,可移植性并不是一个因素。在我看来,.NET 2.0 不需要这种技术。说了这么多,让我们开始吧。
使用代码
.NET 框架在首次引用应用程序域时将应用程序配置文件读入一个静态哈希表。一旦读取,就不能重新读取或修改。这是不幸的,因为它不允许我们调用任何方法或属性来更改此行为。不接受没有变通办法,我开始使用 Lutz Roeder 的 .NET Reflector 窥探 .NET 框架 System.Dll 文件。我发现您可以让框架重新读取配置文件,如果您将其内部变量重置为认为 app.config 文件尚未被读取。这样做很丑陋,但走投无路的人会采取绝望的措施。
以下代码是一个简单的类,用于演示如何执行此操作。我将把它留给读者,将其放入您自己的代码中。
这一切的重点是更改 ConfigurationSettings
类的静态变量 "_configurationInitialized
" 为 false
,并将 "_configSystem
" 设置为空。这样做将使框架将 app.config 文件读入内存。在你离开之前撤销所做的更改非常重要。如果不是这样,使用应用程序现在将指向您的 DLL 的配置文件。确保这种安全的一种方法是将您的配置参数包装在一个类中。我为这个类添加了一个静态的 ConnectionString
方法用于演示目的。它使用 C# "using
" 语句来确保我们的对象被销毁,并且调用 "Dispose
" 以撤销我们的更改。您可以以相同的方式包装对 Enterprise Library 或其他第三方 DLL 的调用。
internal class MyDllConfig : IDisposable
{
private string _oldConfig;
private bool _libCompat;
private const string _newConfig = "mydll.dll.config";
// don't forget to rename this!!
internal MyDllConfig()
{
_libCompat = Assembly.GetAssembly(typeof(
ConfigurationSettings)).GetName().Version.ToString().
CompareTo("1.0.5000.0") == 0;
_oldConfig = AppDomain.CurrentDomain.GetData(
"APP_CONFIG_FILE").ToString();
Switch(_newConfig);
}
protected void Switch(string config)
{
if ( _libCompat )
{
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE",config);
FieldInfo fiInit = typeof(
System.Configuration.ConfigurationSettings).GetField(
"_configurationInitialized",
BindingFlags.NonPublic|BindingFlags.Static);
FieldInfo fiSystem = typeof(
System.Configuration.ConfigurationSettings).GetField(
"_configSystem",BindingFlags.NonPublic|BindingFlags.Static);
if ( fiInit != null && fiSystem != null )
{
fiInit.SetValue(null,false);
fiSystem.SetValue(null,null);
}
}
}
public void Dispose()
{
Switch(_oldConfig);
}
public static string ConnectionString()
{
string cstr;
using ( new MyDllConfig() )
{
cstr = ConfigurationSettings.AppSettings["ConnectionString"];
}
return cstr;
}
}
关注点
我将一个小小的健全性检查放入这个类中,它检查了编写此代码的 System DLL 的版本号。如果检测到另一个版本,则绕过此补丁。
AppDomain 有一个 SetupInformation
属性,它有一个 ConfigurationFile
属性。我发现如果您使用此属性设置应用程序的配置文件名,则会被忽略。使用 SetData
方法会导致类重新初始化此变量,并给我们所需的结果,包括为我们添加应用程序路径到我们的文件名!
Visual Studio IDE 允许您将一个通用的 app.config 文件放入您的 DLL 项目中。将以下行添加到您的后期构建事件将复制并重命名此文件到适当的位置。
Copy $(ProjectDir)app.config $(TargetPath).config