2

Our application creates separate 'sandbox' AppDomains in order to load plug-in code, so that we can unload these plug-ins once we have finished with them.

We make use of the AssemblyResolve event in the sandbox AppDomain, in order to dynamically fix up any assemblies which are not on the sandbox's probing path(s).

When running this code in a unit test, it behaves as expected:

  1. New AppDomain created.
  2. CreateInstanceAndUnwrap called to get a proxy into the AppDomain.
  3. CLR loads assembly containing the proxy type, and marshalls an instance across the AppDomain boundary.
  4. Call our init method on proxy to hook up AssemblyResolve event inside AppDomain.
  5. Start doing work in app domain.
  6. AssemblyResolve event fired as methods are JIT'd, and handled correctly by our custom assembly resolver.

However, when we deploy it to an environment, this behaviour changes:

  1. New AppDomain created.
  2. CreateInstanceAndUnwrap called to get a proxy into the AppDomain.
  3. CLR tries to load ALL assemblies referenced by the assembly in which the proxy type is defined.
  4. Some assembly resolves fail silently (because AssemblyResolve has not been hooked up yet).
  5. Call init method on proxy to hook up AssemblyResolve event inside AppDomain.
  6. Start doing work in app domain.
  7. FileNotFoundException thrown ("could not load assembly..."), because the failed assembly resolution from step 4 was cached, and the CLR doesn't try and re-load the assm.

The key difference is behaviour is that the CLR tried to load every referenced assembly up-front.

I would not have expected this to happen, because none of the code in the proxy type is dependent on any of the code in the references. Why is the CLR trying to load the referenced assemblies when it hasn't JIT'd anything which needs it?

Chris Brook
  • 2,335
  • 20
  • 24
  • 1
    Deployed it to an environment? https://www.youtube.com/watch?v=3m5qxZm_JqM – Moo-Juice Aug 24 '15 at 19:07
  • 1
    Pretty vague, but you cannot predict exactly when the jitter will want to jit a method. You only know "up front" but not how far up front. A simple example is running your test with the Debug build and/or a debugger attached. But running with the optimizer enabled in production, it will try to inline methods. Which requires applying a [MethodImpl(MethodImplOptions.Noinlining)] somewhere as a workaround to stop it from looking too far ahead. There are more scenarios like that, multi-core jit would be another example. – Hans Passant Aug 24 '15 at 20:07
  • Thanks Hans! That would make sense. I did try a Release build etc, but the test case still stubbornly worked... I also wondered if it might be some esoteric security behaviour, or app domain setup etc. Unfortunately, there are a lot of 'moving parts' when it is running in production, so trying to isolate what was affecting the behaviour is a time consuming process! :0) – Chris Brook Aug 25 '15 at 08:41

0 Answers0