插件应用程序和WPF问题?

时间:2013-02-21 17:24:44

标签: c# wpf plugins

我正在开发一个允许第三方插件的项目。我之前使用过插件,但我从未遇到过问题。

我确定我的问题是因为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,但正如你所看到的,这对我现在没有帮助。

我希望我能为您提供足够的信息,任何人都可以提供帮助吗?

1 个答案:

答案 0 :(得分:0)

事实证明我的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;所以我的问题只有一半是固定的。