tags:

views:

597

answers:

5

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.

Thank you in advance for your time.

+1  A: 

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.

U62
How's this done?
Robert H.
Creating a reference in global.asax did not solve my problem.
Robert H.
+1  A: 

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.

Mark
A: 

This doesn't appear to be possible. I cannot get a dynamically loaded assembly from a byte[] array to function the same as those sitting in the /bin folder. I'm tempted to throw some hooks into IIS so it see assemblies that aren't really there, but the intended audience is incorrect for a such kludgy work around.

Robert H.
+1  A: 

My solution to a similar problem may be helpful.

Abtin Forouzandeh
You solution seems to live in the winforms domain. This is not my problem. My problem is specific to .Net Web Applications.
Robert H.
+8  A: 

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;
}
Pavel Chuchuva
Thank you for your time. I'll give this a shot once my schedule permits.
Robert H.