views:

123

answers:

3

Ok, I got a strange one here and I want to know if any of you have ever run accross anything like it.

So I've got this web app that loads up a bunch of dll's through reflection. Basically it looks for Types that are derived from certain abstract types and adds them to the list of things it can make.

Here's the weird part.

While developing there is never a problem. When installing it, there is never a problem to start with. Then, at a seemingly random time, the application breaks while trying to find all the types.

I've had 2 sites sitting side by side and one worked while the other did not, and they were configured exactly(and I mean exactly) the same.

IISRESET's never helped, but this did:

I simply moved all the dll's out of the bin directory then moved them back. That's right I just moved them out of the bin directory then put them right back where they came from and everything worked fine.

Any ideas?

Got some more info

When the site is working I notice this behavior: After IISRESET it still works, but recycling the app pool will cause it to break.

When the site is broken: Neiter IISRESET nor recycling the app pool fixes it, but moving a single dll out then back in fixes it.

Even More Info

So it turns out that IsAssignableFrom is not returning the correct value. I would not have believed it to be true, but I had my logger log the result and the 2 types, and it definitely returned the wrong value. The crazy thing is that the same dll will return different values at different times when comparing the same 2 types.

Yet More Info

The particular class that IsAssignableFrom fails on in located in a file with other classes. If I move the class to its own file, then everything works fine. However, if it is in the same file as other classes(even if it is in its own namespace block) then the Type reference is all wrong. The Type reference will have the correct name and methods, but it has trouble finding the correct constructor.

+2  A: 

I can imagine there concurrency issues accessing the dlls. If multiple users are accessing the page at the same time, and one session attempts to access the dlls, gets exclusive access, all other sessions are failing. Of course, this requires exact timing only achieveable with multiple users, which is why this problem doesn't appear while testing or developing.

In other cases, add extended logging of the loading code, stacktraces of the exceptions being thrown.

Femaref
In this case there was only one user. Me. The process that loads up the dll's only happens at application start
Seattle Leonard
I would add extended logging and debugging. Put a try/catch around the dll loading and analyse the stacktrace and everything else to get to the core of the problem.
Femaref
There is a try catch there. This has only ever happened with a release build. I've tried reproing the issue while debugging with no luck.
Seattle Leonard
So it's a schroediger bug - only there if you don't look. Currently dealing with one of these myself... best of luck.
Femaref
A: 

This could be down to a locking issue. By default, all dlls in the bin directory are loaded by ASP.Net, even if they are not used in the web application. If you are trying to load the types from a specific dll, whilst at the same time ASP.Net is loading that dll into memory, you may get an error due to the file being in use. This may appear as the behaviour you have experienced as it will make a sort-of race condition, and will only present as an error if certain events happen whilst other certain events are happening - even if only a single user is using the site. This may also explain why you do not always get the behaviour.

To stop this, you could put your dlls that you dynamically load types from into a directory inside the bin directory and load them from there.

To be more precise with what the problem is, you would have to show us any error that you get when it fails to load the types (as it may be completely unrelated to a locking issue).

adrianbanks
+1  A: 

It is possible that two (or more) copies of the same assembly are getting loaded into memory. The best way to save yourself time and headache is to strong key your assemblies. If there is a strong naming key only one instance of the assembly will be loaded per appdomain.

More info on assembly binding contexts.

Matthew Whited
Thanks, I hadn't thought of that. However, I just checked, and that particular project already has a strong naming key.
Seattle Leonard
I have been bitten by this beast before... it can be a tricky one to find and understand. Nothing like `typeof(MyObject) != new MyObject().GetType()`
Matthew Whited
Are you doing `Assembly.Load(...)` or `Assembly.LoadFile(...)` It is possible that two difference instances of the assembly is being loaded. It shouldn't if it's strong keyed, but the easier solution is to use an AssemblyResolver instead of manually loading the Assembly.
Matthew Whited
`Assembly.LoadFile()`
Seattle Leonard
Could you change that to either `Assembly.Load(...)` or better still to use an Assembly resolver and the `Type.AssemblyQualifiedName`?
Matthew Whited
`Assembly.LoadFile()` can be very evil. It is possible to get two instances of the same assembly in memory even if it is loaded from the same location. This could also occur if you load the Assembly out of a `byte[]`
Matthew Whited
Your're definitely onto something. This statement returned `false``deriveFromType.Assembly == typeToTest.BaseType.Assembly`could you point me in the right direction for an Assembly resolver?
Seattle Leonard
AssemblyResolvers are events that get attached to the AppDomain. http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyresolve.aspx
Matthew Whited
The solution was to simply change `LoadFile` to `LoadFrom`. Thanks for all your help!
Seattle Leonard