【发布时间】:2013-03-01 08:24:50
【问题描述】:
在this question 之后,我在我们正在开发的旧版 C# 应用程序中成功创建了我的自定义设置提供程序。它通过SettingsProvider 属性引用:
public sealed class MySettings : SettingsProvider
{
...
}
[SettingsProvider(typeof(MySettings))]
internal sealed partial class Settings {}
但是,现在我遇到了另一个问题。
我们的客户端应用程序包含一个自动更新工具,它的实现使得大部分客户端(包括上面的类)都内置到一个 DLL 中(我们在这里称之为 client.dll),然后由 EXE 使用。 EXE 首先检查更新并在需要时从更新服务器下载最新的更新,将所有 DLL 等替换为其较新的版本(包括 client.dll)。为了能够在运行时替换 DLL,它不能静态链接到它们。所以更新后,它会加载 client.dll 并像这样运行它:
Assembly assy = Assembly.LoadFile(
AppDomain.CurrentDomain.BaseDirectory + "client.dll");
object frm = assy.CreateInstance("Client.Forms.MainForm");
Application.Run((Form)frm);
这样做的不幸后果是框架在动态加载的程序集中找不到我的自定义设置提供程序类。我尝试使用LoadFrom 而不是上面的LoadFile,但它没有帮助。到目前为止,我发现的唯一可行的解决方案是在加载器 exe 中实现一个与实际设置提供程序同名的代理类,框架可以找到它。然后代理从客户端程序集实例化真正的设置提供程序并将所有调用委托给它。
这似乎可行,但我对此并不满意。有没有办法帮助框架直接在动态加载的程序集中找到我的类?
更新
我得到的错误信息:
System.Configuration.ConfigurationErrorsException: Failed to load provider type: Client.Properties.MySettings, Client, Version=4.0.1341.0, Culture=neutral, PublicKeyToken=null.
at System.Configuration.ApplicationSettingsBase.get_Initializer()
at System.Configuration.ApplicationSettingsBase.CreateSetting(PropertyInfo propInfo)
at System.Configuration.ApplicationSettingsBase.EnsureInitialized()
at System.Configuration.ApplicationSettingsBase.get_Properties()
at System.Configuration.SettingsBase.GetPropertyValueByName(String propertyName)
at System.Configuration.SettingsBase.get_Item(String propertyName)
at System.Configuration.ApplicationSettingsBase.GetPropertyValue(String propertyName)
at System.Configuration.ApplicationSettingsBase.get_Item(String propertyName)
at Client.Properties.Settings.get_SomeConfigSetting()
at ...
通过调试和日志消息,我确定永远不会调用该类的初始化方法,因此永远不会实例化该类。也就是说,上述异常背后似乎没有隐藏的初始化错误。
还有一点可能很重要:客户端目前在 .NET 2.0 上运行,并且在可预见的未来没有升级计划。
更新 2
我开始按照@jwddixon 的回答建议调查 AppDomain。首先,我想检查 Client.dll 是否真的在与调用者 EXE 不同的应用程序域中结束。所以我列出了当前应用程序域中的程序集,并看到 Client 实际上在那里。但令我惊讶的是,我注意到列表中实际上有两个名为 Client 的程序集 - EXE 和 DLL 具有相同的程序集名称,但版本不同(EXE 为 4.0.0.0,4.0 .1352.0 目前用于 DLL)。到目前为止,我还没有完全意识到这一点,这可能很重要。接下来我将尝试更改 EXE 程序集名称...
更新 3
...这实际上解决了问题! Aaargh...对于我不为人知的前辈发明了这个不知道为什么的扭曲方案,我现在有非常不喜欢的想法...但是感谢你们所有人提出的问题和想法,最终导致了解决方案!
【问题讨论】:
-
尝试使用 Activator 类创建“Client.Forms.MainForm”。 msdn.microsoft.com/en-us/library/system.activator.aspx
-
当您说“框架找不到我的自定义设置提供程序类”时,是否有错误?你能再扩大一点吗?
-
@SimonMourier,请查看我的更新。
-
所以这更像是一个程序集负载问题,对吧?您是否尝试将提供程序类型名称指定为不同的名称,例如“Client.Properties.MySettings, Client”w/o 版本等。
-
哦,好的,我想现在明白了 :-) 如何在任何操作之前挂钩 AppDomain.CurrentDomain.AssemblyResolve 事件,并在请求后指向正确的程序集?
标签: c# reflection .net-assembly settingsprovider