7

按照这个问题,我在我们正在开发的旧版 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的程序集 - EXE 和 DLL 具有相同的程序集名称,但版本不同(EXE 为 4.0.0.0,DLL 目前为 4.0.1352.0 )。到目前为止,我还没有完全意识到这一点,这可能很重要。接下来我将尝试更改 EXE 程序集名称...

更新 3

...这实际上解决了问题!Aaargh... 对于我不为人知的前辈发明了这个不知道为什么的扭曲方案,我此刻有非常不喜欢的想法...但是感谢你们所有人提出的问题和想法,最终导致了解决方案!

4

1 回答 1

1

我还没有尝试过,但是类似的东西怎么样:

AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
AppDomain domain = AppDomain.CreateDomain("myAppDomain", null, setup)
setup.ApplicationBase = file;

Assembly assy = domain.Load(AssemblyName.GetAssemblyName(
AppDomain.CurrentDomain.BaseDirectory +
 "client.dll"));

object frm = assy.CreateInstance("Client.Forms.MainForm");
Application.Run((Form)frm);
于 2013-03-06T10:56:07.497 回答