2010/10/28

GetAssemblies missing dll's

I have a couple ASP.Net MVC web applications that allow additional functionality by dropping new class library dll's into the bin directory.  This causes new options, tools, products, workflows, etc to be enabled to the user with just a pushing out a new class library.  We've moved away from using an DI/IoC tool (StructureMap/Castle Windsor) because of seeing some memory leaks and having some maintenance issues of the xml files needed to use them.

Instead I decided to go the route of using existing functionality built into the .Net framework.  There is this nifty little static method AppDomain.CurrentDomain.GetAssemblies() which:
Gets the assemblies that have been loaded into the execution context of this application domain.
So, I figure this being ASP.Net, all the dll files in the bin directory would be loaded up, right?  I run the solution and a bunch Assemblies are returned (mscorlib, System.Web.Mvc, Stuff.I.want.dll, More.Stuff.I.Want.dll) page loads and I can see everything it there and happy. A bit more testing happens and then check-in so it gets put out on the web server.
I run through some testing there to make sure there is no real differences between IIS7 and Visual Studio development web server.  Everything looks great. I've removed some external dependencies, lowered the memory footprint, and eased readability. Fantastic! Time to turn it over to have others really kick the tires.

A couple hours go by and then it happens. "Hey Paul! I'm not seeing any of these options I had the last time I opened the page." So I look, the dll's are there.  There were no other code changes to remove them. Let's run local.  Everything looks fine.  I check that results from this particular call are being cached. Everything seems fine.  I change some methods from static to instance, just in case, and deploy.

Again, everything is going along just fine, until the next morning. "Paul. Seriously, are you messing with me? These options are gone again." Me: "%&$(*$%" Directory looks fine. Ok, going to move some stuff out of extension methods and directly into the main assembly for this backend assembly. Lather, rinse, repeat.

Time passes... "Paul, WTF?" Me: "Are you friggin kidding me?" Nothing, NOTHING, is static now in my code.  Nothing is in an extension method, I am very close to having all this functionality in one big DoThisCrap method.

To the Googles!!!

You remember that "Gets the assemblies that have been loaded into the execution context of this application domain." part earlier? Yeah me neither.

So what was happening, as best as I can tell, was the fresh code right after a deployment (or every time I opened in the VS dev server) ASP.Net loaded every dll in the bin as I hoped.  On subsequent page visits, ASP.Net learned that some files were not needed on the last load and no code was directly instanciating them so they weren't loaded. This means they didn't show up.

What to do? Well, we can get the current directory from AppDomain.CurrentDomain.BaseDirectory property.  From there it's a simple System.IO.Directory.GetFiles call to plow the directory with various search options.

/*
this can be pointed to specific sub folder using string.format
*/
var path = AppDomain.CurrentDomain.BaseDirectory;

/*
you can add file name matching criteria here if the assemblies you are looking for match a naming convention
*/
var files = Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories);

and now we can perform logic on the files array.

Since we are looking directly at a folder path, there is no issue of whether previous runs loaded the assemblies into the AppDomain.  However, there is the additional cost of going to disk to get results.

Comments