views:

333

answers:

3

I have a little bit of code that loops through the types currently loaded into an AppDomain that runs in an ASP.NET application. Here's how I get the assemblies:

var assemblies = AppDomain.CurrentDomain.GetAssemblies();

When the application first starts up there is no problem and all the types I expect are present. But when I update the Web.config or kill the w3p.exe process (or the process gets recycled for whatever reason) only some of the types I'm expecting are available. When I step through with a debugger I notice that certain assemblies from the private search path (the bin directory of my application) haven't been loaded. I was under the assumption that all assemblies were loaded at application start and restart whether or not they were immediately required. But in the case of restarting this doesn't seem to be happening unless those assembly files have been updated.

What I require is to collect type information at start-up for use later. But since during a restart the types aren't available it reeks havoc later on when the type information needs to be used. So with that in mind how can I solve or work around this deficiency?

+1  A: 

Assemblies are loaded on demand, so it could be that you did not used any type contained in these assemblies yet.

codymanix
That's true, I haven't loaded any of the types at app start up. The problem is I need the type information at app start up so I can use that info later on. If the info isn't available at start up the app can potentially crash later on.
Jonathon Watney
you can use the static method Assembly.Load() to ensure all of your required assemblies are loaded when you need them.
codymanix
I can't use Aseembly.Load() because I don't have the assembly names available. You might want to check out Nader's answer to see where I'm at.
Jonathon Watney
+1  A: 

As a part of startup, can you explicitly load the assemblies you care about?

You would have to know ahead of time which assemblies you would need.

Scanning the filesystem to find out which assemblies have been shipped along with your app may be a useful idea, but it won't help for GAC loaded assemblies...

Nader Shirazie
I was thinking of explicitly loading the assemblies. I only need the private assemblies so far so I could just load everything from the private search path. I'm not sure which is the best way to accomplish that though. Assembly.Load? Assembly.LoadFile? Assembly.LoadFrom?
Jonathon Watney
Assembly.Load in general is the preferred approach, since it is closest to normal loading mechanism. See http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx for advantages and disadvantages, and http://blogs.msdn.com/suzcook/archive/2003/09/19/57248.aspx for a bit more info.
Nader Shirazie
Thanks for the links, I've already looked those over. I think I'd have to use LoadFrom or LoadFile since I only have file paths to work with. I know when I've used LoadFile before I'd have problems updating assemblies during a deploy due to assembly files being locked, presumably by LoadFile. I think LoadFrom is right for me but I'm not sure I completely understand its implications.
Jonathon Watney
If you only have the paths to work with, can you inspect those assemblies to figure out the paths? Its important to get the binding context right. Also, as far as file lock issues, you should shut down the app pool while deploying - that will shut down the IIS process and prevent locks. If you don't want to do this, the other option is to do what ASP.NET does: create shadow copies (http://www.techbubble.net/Blog/tabid/57/EntryId/148/Locked-assemblies-when-using-lt-probing-privatePath-quot-quot-gt.aspx)
Nader Shirazie
Nader, thanks again. I'm just not sure how to determine which binding context is correct for me. So far LoadFrom is working and I've verified, as far as I can, that I have the expected behavior. But then again, that's how it seemed before I noticed I had this problem. :)
Jonathon Watney
If you let .NET work normally, it will use the Load context. If for some reason, there is an attempt to load an assembly into the Load context, you may have an issue. You can probably handle that by handling the AppDomain.AssemblyResolveEvent though... see http://stackoverflow.com/questions/416468/weird-behaviour-when-mixing-loading-of-assemblies-using-assembly-loadfrom-and-ass for something similar. We take a similar approach (AssemblyResolve + LoadFrom), and it has worked well so far...
Nader Shirazie
I think I found a suitable solution using the preferred approach of Assembly.Load. Since I have the paths for the assemblies I'm able to lookup their names with AssemblyName.GetAssemblyName and then call Assembly.Load using the assembly name. So far everything is working and this should avoid any problems so far regarding different contexts.
Jonathon Watney
Very nice. (extra chars)
Nader Shirazie
+1  A: 

You can use

AssemblyName[] assemblies = Assembly.GetCallingAssembly().GetReferencedAssemblies();

This way, you get all assemblies that are referenced from the assembly from which you are calling these method.

codymanix
My calling assembly does not necessarily reference the types I'm after though.
Jonathon Watney
But maybe they are referenced by another assembly which is referenced by your assembly. You could walk the whole tree of indirectly referenced assemblies to get all assemblies/types you want.
codymanix
Ah, I see. I could do that. I'll have to see how this contributes to start up time. Thanks.
Jonathon Watney
Turns out I can't do this since the calling assembly and even the executing assembly do not, even indirectly, reference the types I'm interested in.
Jonathon Watney