Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I Dynamically Load Assemblies Not on Disk into an ASP .Net Web Application?

Tags:

c#

asp.net

I'm writing a prototype to prove the feasibility of something I'm working on. Basically, it requires loading assemblies not on disk into an application domain. On the surface, it sounds easy. In fact, it's child's play in the WinForms world where a process is a process.

For the ASP.Net Web Applications, it's a bit squirrelly. I've got it working 99.99%. The current method is somewhat working like this:

public class AppDomainManager : System.AppDomainManager
{
    PhantomAssemblyLoader m_phantomAssemblyLoader;
    public AppDomainManager()
    {
        m_phantomAssemblyLoader = new PhantomAssemblyLoader();
    }

    public override void InitializeNewDomain(AppDomainSetup appDomainInfo)
    {
        m_phantomAssemblyLoader.Attach(AppDomain.CurrentDomain);
    }
}

public class PhantomAssemblyLoader
{
    public PhantomAssemblyLoader()
    {
    }

    public void Attach(AppDomain appDomain)
    {
        appDomain.AssemblyResolve += new ResolveEventHandler(AssemblyResolve);
        appDomain.DomainUnload += new EventHandler(DomainUnload);
    }

    public void Detach(AppDomain appDomain)
    {
        appDomain.AssemblyResolve -= AssemblyResolve;
        appDomain.DomainUnload -= DomainUnload;
    }

    void DomainUnload(object sender, EventArgs e)
    {
        this.Detach(sender as AppDomain);
    }

    private Assembly AssemblyResolve(object sender, ResolveEventArgs args)
    {
        Assembly asssembly = Assembly.Load(BlackMagic.GetBytes(sender, args));
        return asssembly;
    }
}

The problem seems to be that a new AppDomain is instantiated and unloaded for each page load. The above code loads the required assembly, unloads it, loads it again and so on. I know this is happening because the static data within these phantom assemblies does not persist between page loads.

The correct solution can load these phantom assemblies into the same context as those assemblies found in the /bin folder. These are loaded when the application starts and are never unloaded during the session.

like image 866
Robert H. Avatar asked Jun 08 '09 18:06

Robert H.


3 Answers

If you read documentation on AppDomainManager you will see a note:

Do not use AppDomainManager to configure an application domain in ASP.NET. In ASP.NET, configuration must be handled by the host.

Therefore, you should not use environment variables or registry to customize AppDomainManager.

I believe you can achieve what you want by simply adding AssemblyResolve event handler to AppDomain.CurrentDomain. I created simple website and it works as expected - dynamic assembly doesn't get unloaded between page loads.

protected void Page_Load(object sender, EventArgs e)
{
   AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(AssemblyResolve);
   Assembly assembly = Assembly.Load("PhantomAssembly");
   Type t = assembly.GetType("PhantomAssembly.Test");
   MethodInfo m = t.GetMethod("GetIt");
   Response.Write(m.Invoke(null, null));
   t.GetMethod("IncrementIt").Invoke(null, null);
}

private static Assembly AssemblyResolve(object sender, ResolveEventArgs args)
{
   Assembly asssembly = Assembly.Load(File.ReadAllBytes(@"C:\PhantomAssembly.dll"));
   return asssembly;
}
like image 156
Pavel Chuchuva Avatar answered Nov 04 '22 08:11

Pavel Chuchuva


If the problem is that the AppDomain is getting created and destroyed on each page request, surely that can be solved by holding a reference to it in the ASP.NET Application state. You could create it once in the Global.asax for example.

like image 29
U62 Avatar answered Nov 04 '22 08:11

U62


You might want to check out the MSDN article on ASP.NET Application Life Cycle and investigate loading your Assembly in the Application_Start event.

like image 39
Mark Avatar answered Nov 04 '22 07:11

Mark