插件应用程序和WPF问题
本文关键字:问题 WPF 应用程序 插件 | 更新日期: 2023-09-27 18:00:38
我正在做一个需要允许第三方插件的项目。我以前使用过插件,从来没有遇到过问题。
我确信我的问题是因为WPF不喜欢我使用Assembly.LoadFile(file)&Activator.CreateInstance(t)!
我遇到的错误是:
The component 'Servus.Forms.MainWindow' does not have a resource identified by the URI '/Servus;component/forms/mainwindow.xaml'.
它显示在我的MainForm构造函数中,位于:InitializeComponent();
如果我在加载MainForm后加载插件,它加载时没有问题,但是当打开任何其他表单(我的应用程序中有很多)时,我会遇到与有关的问题,但会出现特定表单的相关错误。
我也试着加载插件在那里自己的AppDomain像这样:
PluginDomain temp = new PluginDomain();
PluginBase tempPlug = temp.GetPlugin(file);
具有以下类别:
public class PluginDomain
{
public AppDomain CurrentDomain { get; set; }
public ServusAssemblyLoader CurrentAssemblyLoader { get; set; }
private readonly Random _rand = new Random();
public PluginDomain()
{
}
public PluginBase GetPlugin(string assemblyName)
{
try
{
string appBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var ads = new AppDomainSetup { ApplicationBase = appBase, PrivateBinPath = appBase, ShadowCopyFiles = "true" };
CurrentDomain = AppDomain.CreateDomain("ServusDomain_Plugin_" + _rand.Next(0, 100000), null, ads);
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
CurrentAssemblyLoader = (ServusAssemblyLoader)
CurrentDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(ServusAssemblyLoader).FullName);
AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve;
return CurrentAssemblyLoader.Load(assemblyName);
}
catch (Exception e)
{
CConsole.WriteLine("Error: " + e.Message);
}
finally
{
CurrentAssemblyLoader = null;
AppDomain.Unload(CurrentDomain);
}
return null;
}
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string[] parts = args.Name.Split(',');
string file = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "''" + parts[0].Trim() + ".dll";
return Assembly.LoadFrom(file);
}
}
public class ServusAssemblyLoader : MarshalByRefObject, IAssemblyLoader
{
public PluginBase Load(string file)
{
Assembly asm = Assembly.LoadFrom(file);
foreach (Type t in asm.GetTypes())
{
if (t.IsSubclassOf(typeof(PluginBase)))
{
return (PluginBase)Activator.CreateInstance(t);
}
}
return null;
}
}
public interface IAssemblyLoader
{
PluginBase Load(string file);
}
这返回一个TransparentProxy对象,如下所示:
{System.Runtime.Remoting.Proxies.__TransparentProxy}
然而,我不确定如何使用它,因为我希望它返回一个PluginBase对象。
我读到很多人也有这个问题,他们的答案是使用新的AppDomain,但正如你所看到的,这对我现在没有帮助。
我希望我已经给你提供了足够的信息,有人能帮忙吗?
原来我的PluginDomain类中有一些错误。
修复#1:
替换:
return (PluginBase)Activator.CreateInstance(t);
带有:
(PluginBase)asm.CreateInstance(t.ToString());
修复#2:
删除:
AppDomain.Unload(CurrentDomain);
修复#3:(纯粹用于调试)
替换:
return CurrentAssemblyLoader.Load(assemblyName);
带有:
PluginBase obj = CurrentAssemblyLoader.Load(assemblyName);
return obj;
编辑:
需要注意的是,新的AppDomain将无法访问旧的AppDomain中的对象;所以我的问题只解决了一半。