如何使动态加载的程序集中的设置提供程序可用于反射?

时间:2013-03-01 08:24:50

标签: c# reflection .net-assembly settingsprovider

关注this question后,我在我们正在开发的旧版C#应用中成功创建了自定义设置提供程序。它通过SettingsProvider属性引用:

public sealed class MySettings : SettingsProvider
{
    ...
}

[SettingsProvider(typeof(MySettings))]
internal sealed partial class Settings {}

然而,现在我遇到了另一个问题。

我们的客户端应用程序包含一个自动更新工具,它的实现使得大部分客户端(包括上面的类)构建到DLL中(我们在这里称之为 client.dll ),然后由EXE使用。如果需要,EXE首先检查更新并从更新服务器下载最新的更新,用其较新版本(包括 client.dll )替换所有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,但它没有帮助。到目前为止,我发现的唯一可行的解​​决方案是在loader 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 ......对于那些为谁知道原因而发明这种扭曲方案的未知前辈,我现在有非常不满意的想法......但是对你们所有人提出的问题和想法最终导致解决方案感到荣幸!

1 个答案:

答案 0 :(得分: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);