Lazycoder

27Oct/043

Loading code-behind assemblies dynamically

ComputerZen.com – Scott Hanselman’s Weblog – Moving the Code-Behind Assemblies/DLLs to a different folder than /BIN with ASP.NET 1.1

I’m doing something similar to what Scott is doing, except I’m trying to either link or load the code-behind assemblies dynamically at run time.

I’m designing a plug-in framework for a project I’m working on. The idea is that other developers can reference our plug-in framework, implement our IPlugin interface, make a reference to their plugin in an XML config file, either for a specific page or for all pages in the application, and our plugin loader control will read the config file and instantiate the plugins specifed. Basically letting other developers add functionality to our application without their changes getting clobbered by our upgrades and new releases. Roy’s article is a great starting point, but it works best with detached assemblies. The code behind model in ASP.NET presents some interesting challenges. You can put the code behind assemblies in the /bin directory and have them automagically linked during the JIT compile, but as Scott points out in his post, that can clutter up the /bin directory a little. It also makes it a little difficult to version plugins. I want the developers to just plop the plugin in a /plugins directory and have it “just work”.

It’s pretty simple to load assemblies at runtime and create instances of the classes you want, once you grok the AppDomain and the Activator.CreateInstance method at least.


            string baseDir = AppDomain.CurrentDomain.BaseDirectory;
            ObjectHandle hndl = Activator.CreateInstanceFrom(baseDir + @"hellosTestAssembly.dll","TestAssembly.Class1");
            IHello.IHello newObj = (IHello.IHello) hndl.Unwrap();
            lblHello.Text = newObj.HelloWorld();

Scotts “probing” solution would work, but it requires the devs to modify the web.config, which could get clobbered. I’m starting to warm up to it a little more now that I’m thinking about it. At least until I solve the big problem, setting the probing property at runtime. I’m going to investigate the AppDomain.RelativeSearchPath property and the AppDomain.AppendPrivatePath method and see if I can set it at runtime, at least during application startup. I think if I were to do too much with them that I might impact the performance of the application. I’m also wondering if I’ll have to create a new AppDomain, like Roy did in his second article, and unwrap the proxies? I hope not, I’m pretty sure there’s a performance hit when you are crossing AppDomain boundries. The crux of this problem is that when you try to load a web control that uses the code behind model into your application you aren’t just loading one assembly dynamically, you are loading two and the second one isn’t created until runtime (essentially) and then not until the control is referenced. But the second one can’t be created until the first one is loaded and the appropriate code-behind class is instantiated. If I can load the code behind assemblies into the AppDomain during the application startup or link to them during the JIT compile, then loading the web controls is a snap.

If anyone has any suggestions or experience in these matters (e.g. “Scott you dummy you’re missing the obvious and making it more complicated than it needs to be!”) feel free to drop me a line, comment, or trackback to this post. I’ll be posting more on this later in the day/week as I learn more.

n.b. My first name is also Scott. The Scott I’m referring to in my “Scott you dummy…” line above is myself, not Scott H

Filed under: .NET Leave a comment
  • http://www.computerzen.com Scott Hanselman

    Hey, seriously “Scott you dummy you?re missing the obvious and making it more complicated than it needs to be!”

    ;)

    The AppDomain/Searchpath/Objecthandle.Unwrap stuff is WAY to complex for this problem.

    You’re creating all that stuff based on the concern that the web.config might get “clobbered.”

    Simply make it a requirement that they don’t mess with web.config. Full stop.

    You can’t change the probing path programmatically. You change it either in the machine.config or the web.config.

    IMHO.

  • Derek Greer

    Hey Scott. It sounds like I’m trying to do the exact same thing you were and was wondering if you ever found a solution. I’m developing a plugin framework for web apps and am trying to figure out a way to allow the plugin developer to drop everything under a plugins directory. I’ve tried AppendPrivatePath and have tried registering a handler for the AssemblyResolve event, but both seem to only work if you aren’t doing a Server.Transfer(). I don’t think using the Web.config file would be a good solution for me, as I want the plugin developer to drop their plugin under “~/plugins/[pluginname]/” which I of course would not know at config time. So, did you ever find a solution?

  • Scott

    What I ended updoing in the short term was dropping the plugin assemblies into the /bin directory of the web app. I’m still not happy with that. I’ve read the Fusion teams web logs up and down several times. It doesn’t sounds like what we want to do is possible. The best solutions are the one I ended up with and the one that Scott H proposed in his post.

    I haven’t looked to see how this is being treated in .NET 2.0. I’m wondering if partial classes can be spread between separate assemblies. My gut is telling me “no”. It looks like the Assembly loading mechanisms are getting less flexible in 2.0.