I am working on a project where allowing 3rd-party plugins is required. I have worked with plugins before and I never had a problem.
I'm sure my problem is because WPF doesn't like me using Assembly.LoadFile(file) & Activator.CreateInstance(t)!
The error I encounter is:
The component 'Servus.Forms.MainWindow' does not have a resource identified by the URI '/Servus;component/forms/mainwindow.xaml'.
which shows in my MainForm constructor at: InitializeComponent();
If I load the plugins after loading the MainForm it loads without issues, however when opening any other forms(there are many in my application) I experience the same issue as about but with the relevant error for that particular form.
I have also tried to load the plugins in there own AppDomain like this:
PluginDomain temp = new PluginDomain();
PluginBase tempPlug = temp.GetPlugin(file);
With the following classes:
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);
}
This returns an TransparentProxy object like this:
{System.Runtime.Remoting.Proxies.__TransparentProxy}
However I am unsure how to use this as I was expecting it to return a PluginBase Object.
I have read that many people have also have this issue, they have answers that say to use a new AppDomain, but as you can see this doesn't help me right now.
I hope I have provided you enough information, can anyone help?