I'm trying to make some sort of plugin system for asp.net webforms using MEF.
So far I've come with a solution where the host website will search in its plugin folder to load other websites called Module. A module (plugin) is just another website project, so it has its own assemblies in its bin subfolder.
As you certainly already know, an ASP.NET application won't load dll outside its bin folder. So if I try to access a module page (eg: plugins/MyModule/Page.aspx). I'll get an error saying that the server can't load the assembly MyModule. I can throw the module's assembly in the main bin folder and everything will work, but I would like to keep all the module files in the same folder.
So I'm looking for a way to load assemblies outside the bin folder. I've tried messing with the web.config file but couldn't come with a working solution.
Then I came accross the BuildManager class and wrote this code :
string pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plugins");
foreach (string f in Directory.GetDirectories(pluginPath))
{
string binPath = Path.Combine(f, "bin");
if (Directory.Exists(binPath))
{
foreach (String file in Directory.GetFiles(binPath, "*.dll"))
{
Assembly a = Assembly.LoadFrom(file);
BuildManager.AddReferencedAssembly(a);
}
}
}
It search the plugin folder for any other subfolder containing a bin folder and load the corresponding assemblies using the BuildManager. To make this code works I have to call it in the PreApplicationStartMethod of the global.aspx assembly.
Now when I navigate to the plugin page (plugin/MyModule/Page.aspx) it won't give me the previous error but the page is blank. I've checked the source and there is no html, nothing. I've tried to debug the page but the Page_Load method is never called. So I guess somehow the code behind Page.aspx is never called.
Edit:
So after searching a bit more I found a solution there:
BuildManager Resolving Page Inheritance
When I load a module assembly, I store its reference in a dictionnay. Then in the event handler to AppDomain.CurrentDomain.AssemblyResolve I return the corresponding module assembly.
I got the same problem. I fixed by resolving assembly as below
protected virtual void Application_Start(object sender, EventArgs e)
{
//...
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var currentAssemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in currentAssemblies)
{
if (assembly.FullName == args.Name || assembly.GetName().Name == args.Name)
{
return assembly;
}
}
return null;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With