17

Given a loaded Assembly is there a way (in code) to determine which of the 3 load contexts it was loaded into (default Load, LoadFrom, or Neither)?

In Suzanne Cook's "Choosing a Binding Context" article, there are some disadvantages that occur when an assembly is loaded into the LoadFrom. In particular, my library uses deserialization and encounters an InvalidCastException when loaded into the LoadFrom context.

Currently my library fails very late (it fails when it executes the problematic deserialization code--see my example). I'd like to make it fail much earlier in these circumstances by detecting the context it is loaded into and throwing an exception if it is not loaded into the default Load context.

zastrowm
  • 8,017
  • 3
  • 43
  • 63
Matt Smith
  • 17,026
  • 7
  • 53
  • 103
  • IMO one (not very elegant) solution would be to subclass Assembly, rewrite the Load methods and add custom flags when one of the methods is used. – keenthinker May 01 '14 at 16:09
  • 1
    @pasty The Load method that is used doesn't necessarily result in the assembly being loaded into a particular context. I.e. Calling Assembly.Load does not always cause the assembly to be loaded in the default Load context. Furthermore, I am not in control of the code loading the assembly. – Matt Smith May 01 '14 at 16:54
  • Have you tested the behaviour of the `Assembly.HostContext` property? It's of the `long` type. I peeked in that property using JustDecompile, but I still have no clue about how can its value map to those 3 categories. – Ondrej Janacek May 06 '14 at 17:32
  • I know you won't like like it :-) but you can subscribe to AppDomain.AssemblyLoad event and walk the stack (using the StackFrame class). I don't think there is any other easier way. – Simon Mourier May 06 '14 at 17:47
  • @SimonMourier, unfortunately, by the time my code has a chance to run, the Assembly may have already been loaded. So, I'm looking for an "after the fact" way. Regardless, it's not clear to me how walking the stack would help you determine what load context the assembly ended up in. – Matt Smith May 06 '14 at 18:29
  • A StackTrace instance gives you a list of StackFrames, StackFrame has a GetMethod() method that can ultimately tell you if the event comes from the Assembly.LoadFrom or Load or whatever. – Simon Mourier May 07 '14 at 05:30
  • @SimonMourier, ah. But as I stated in a previous comment, the Load method that is used doesn't necessarily indicate the load context where the assembly is loaded. – Matt Smith May 07 '14 at 13:18

2 Answers2

4

Instead of identifying the context of the assembly, you could test the behavior of it. For example, for serializing, the serializer will call Assembly.Load and that assembly must match the assembly of the object being serialized. A match can be tested for by checking the CodeBase.

private static bool DoesAssemblyMatchLoad(Assembly assemblyToTest)
{
    try
    {
        var loadedAssembly = Assembly.Load(assemblyToTest.FullName);
        return assemblyToTest.CodeBase == loadedAssembly.CodeBase;
    }
    catch (FileNotFoundException)
    {
        return false;
    }
}
Josh
  • 2,259
  • 4
  • 22
  • 25
  • This seems to work for all cases I've tried (Load,LoadFrom and LoadFile). It has the nice feature that it will only actually Load a new assembly in the case where there is not a match. While it doesn't technically answer the question--it does solve my problem nicely. – Matt Smith May 06 '14 at 19:41
2
  • reflection-only context: Assembly.ReflectionOnly == true

  • no context (dynamic): Assembly.IsDynamic == true

  • no context (Load(byte[])): Assembly.Location == null

  • default context: either Assembly.GlobalAssemblyCache == true or Assembly.Location begins with property CodeBase

  • load-from context: anything else assuming you would not load from from code base

CodeFox
  • 3,321
  • 1
  • 29
  • 41