我正在开发的插件(我们称之为PLUGIN)正在使用主软件中的两个汇编文件(让它称为PARENT)。一旦PARENT更新为新版本(并且它每周发生几次),我希望我的PLUGIN动态加载新版本的依赖项,而不必强迫我重新编译。
PARENT将其插件作为源代码文件加载,并及时编译它们。由于我希望我的代码在DLL中,因此我的Loader.cs文件通过反射从我的DLL调用函数。
以下是Loader.cs的代码。
// error handling removed for better readability
public Loader()
{
assembly = Assembly.LoadFile(dllPath);
type = assembly.GetType("PLUGIN.PLUGINStarter");
instance = Activator.CreateInstance(type);
}
public override void Dispose()
{
type.InvokeMember("Dispose", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, instance, null);
base.Dispose();
}
public override void OnButtonPress()
{
type.InvokeMember("ShowForm", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, instance, null);
}
现在PLUGIN命名空间中的PLUGINStarter类如下所示。
class PLUGINStarter
{
private PLUGIN plugin = null;
/// <summary>
/// This is loading PARENT.exe and PARENTSomeOtherFile.dll dependencies.
/// </summary>
public PLUGINStarter()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) =>
{
var fullAssemblyName = new AssemblyName(eventArgs.Name);
// this is not executed when PARENT version changes
MessageBox.Show(fullAssemblyName.Name, "Loading assembly...");
if (fullAssemblyName.Name.Equals("PARENT"))
{
// AppDomain.CurrentDomain.FriendlyName will handle the case where PARENT.exe is re-named
var found = Assembly.LoadFile(Path.Combine(Environment.CurrentDirectory, AppDomain.CurrentDomain.FriendlyName));
return found;
}
else if (fullAssemblyName.Name.Equals("PARENTSomeOtherFile"))
{
var found = Assembly.LoadFile(Path.Combine(Environment.CurrentDirectory, "PARENTSomeOtherFile.dll"));
return found;
}
else
{
return null;
}
};
Initialize();
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void Initialize()
{
// the PARENT's assemblies are referenced in the PLUGIN class
plugin = new PLUGIN();
}
public void ShowForm()
{
plugin.ShowForm();
}
public void Dispose()
{
plugin.Dispose();
}
}
当PARENT更新为新版本时,不会触发事件。为什么呢?
编辑#1
澄清:PARENT加载(及时编译)Loader.cs加载PLUGIN.dll,它依赖于来自PARENT的程序集(主要是 PARENT.exe 本身)。
编辑#2
PARENT软件手动更新。用户从互联网(产品的网站)下载它。然后用户将我的PLUGIN.dll复制到PARENT的“插件”目录中。
然后我能够在Loader.cs中捕获以下异常。
[07:55:19.822 D] [PLUGIN] Loading DLL 'C:\PNT\PARENTNew\Plugins\PLUGIN\PLUGIN.dll'.
[07:55:19.826 D] [PLUGIN] Exception loading assembly 'System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileLoadException: Could not load file or assembly 'PARENT, Version=6.2.8113.191, Culture=neutral, PublicKeyToken=21a554ab5c01ae50' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
at PLUGIN.PLUGINStarter..ctor()
--- End of inner exception stack trace ---
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Activator.CreateInstance(Type type)
at PLUGINLoader.Loader..ctor() in c:\PNT\PARENTNew\Plugins\PLUGIN\Loader.cs:line 42'.
编辑#3
我认为这是可能的,如Is it possible to replace a reference to a strongly-named assembly with a "weak" reference?所述,但由于一些奇怪的原因,它在我的申请中失败了。
编辑#4
我通过删除PLUGINStarter并将程序集解析代码移动到Loader.cs的构造函数来解决了这个问题。现在,尽管装配版本错误,但一切都很好地解决了。
答案 0 :(得分:0)
我很乐意发表评论,所以我把它作为答案。
我仍然不明白为什么要加载已加载的PARENT程序集或者如何更新&#34; PARENT ...
如果加载了dll,通常无法卸载它。您必须创建一个新的AppDomain才能使其正常工作。
所以我看到它,你运行你的PARENT,它加载PLUGIN,然后附加事件。
根据http://msdn.microsoft.com/en-us//library/ff527268.aspx
当您为AssemblyResolve事件注册处理程序时,只要运行时无法按名称绑定到程序集,就会调用该处理程序。例如,从用户代码调用以下方法可能导致引发AssemblyResolve事件:
AppDomain.Load方法重载或Assembly.Load方法重载,其第一个参数是一个字符串,表示要加载的程序集的显示名称(即Assembly.FullName属性返回的字符串)。
AppDomain.Load方法重载或Assembly.Load方法重载,其第一个参数是一个AssemblyName对象,用于标识要加载的程序集。
Assembly.LoadWithPartialName方法重载。
AppDomain.CreateInstance或AppDomain.CreateInstanceAndUnwrap方法重载,用于实例化另一个应用程序域中的对象。
这意味着您必须显式加载程序集(并且无法自动执行)以触发事件。
所以我相信&#34;更新&#34;父母在这里至关重要。你怎么做呢?
修改
根据您的修改,我相信您的答案可以在这里找到:If I rebuild a dll that my project references, do I have to rebuild the project also?
This link还提到严格强制引用程序集的版本以及如何避免它。
答案 1 :(得分:0)
如编辑#4中所述,装配事件未能很快注册。
我通过删除PLUGINStarter并将程序集解析代码移动到Loader.cs的构造函数来解决了这个问题。现在,尽管装配版本错误,但一切都很好地解决了。