Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

asp.net dynamically loading assemblies

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.

like image 732
cpaulus Avatar asked Mar 23 '23 02:03

cpaulus


1 Answers

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;
    }
like image 109
hoangitk Avatar answered Apr 05 '23 21:04

hoangitk