Assembly.LoadFrom is a weirdo.

1. It is order dependent. If you call Assembly.LoadFrom on multiple assemblies with the same assembly name, you will always get the first copy, even though those assemblies have different file paths.
2. Assemblies loaded by Assembly.LoadFrom cannot be seen by assemblies in the default load context. If you want the assembly to be seen in the default load context, you have to load it in the default load context, or return it through AssemblyResolve event.
3. Assembly returned from Assembly.LoadFrom may end up in default load conext, or LoadFrom load context, depending on whether the same file can be found in default load context or not.
4. Dependencies of Assembly.LoadFrom may be satisfied from application base, or the assemblies’s directory
5. Why are there different load contexts at all?

But if it is so confusing, why have it in the first place?

It was designed to enable the add-in scenario. You can imagine that an add-in will live in a different directory than the host, and all the dependencies of the add-in live alongside the add-in. LoadFrom solves the problem of loading the add-in, and its dependencies.

This is particularly useful for COM Interop (thinking unmanaged host with managed add-ins). On majority cases the managed add-ins do not reside in the application’s directory. You either put the add-ins into GAC, or you have to use Assembly.LoadFrom.

But the model is difficult to extend to multiple add-ins scenario. The problems include but not limited to 1. How to manage dependencies of those add-ins. 2. How do those add-ins communicate to each other.

Over the years people realize Add-in is a complex problem, and can’t be solved alone with LoadFrom (This is almost clear right after we shipped .Net framework v1.0). Right people is thinking about this problem. You may see a proposal in future version of .Net framework.

Given the greatest confusion it brings to people, and the inability to solve the add-in problem, maybe, in the future you will see Assembly.LoadFrom being deprecated.

Comments (8)

  1. Per Bergland says:

    Hmmmm…. Does that mean that the COM interop loads the registered assembly using LoadFrom and dependencies found in the same directory as the main assembly should load automatically? That isn’t my experience, especially when using COM+.


  2. COM+ has its own way of registration and activation, which I has no knowledge of.

    I was talking about local COM, specifically, RegAsm and RegAsm /codebase option.

  3. Matan says:

    I do not know where to ask this (I hope someone who can help me sees this 😉 ), so sorry if it’s the wrong place, however I think it’s closely related to the post’s subject.

    An unmanaged host program loads my strong-named managed plugin assembly ("Plugin.dll"). All the assemblies that Plugin.dll references (one of them is "Reference.dll", which is strong-named) are included with it in the same directory.

    Now, there are other managed plugins for this application, some of which use a different (older) version of Reference.dll.

    During the development of Plugin.dll, it is not strong-named, and also the Reference.dll that I use is not strong-named. During development it works fine, along with other already-released plugins which DO use an older version of Reference.dll.

    However, when I compile Plugin.dll and Reference.dll both with a strong name and run the host app (which loads the other plugins too), only the old version of Reference.dll is loaded. I guess it’s loaded before the new version and then when it comes to the static reference of the new version it thinks it’s "good enough" – although from what I’ve been reading strong-naming it should make different versions unique.

    Plugin assemblies are registered for COM Interop, and none of them are in the GAC (it’s not an option). Additionally, all of them are signed with the same keypair (I don’t know if it matters at all in this case).

    Thanks in advance!


  4. Matan says:

    Thanks for your fast reply!

    Just to note, I solved my problem, but I don’t know how, and I don’t know if I’ll ever be able to reproduce it again. But I’m not complaining. 🙂

    As for what you suggested –

    I had turned on logging (set ForceLog to 1 too).

    It made lots of log entries (that’s expected since a lot of .NET plugins are loaded in that unmanaged host app). For each .NET plugin it had one entry that indicated failure (it tried to load it from the appbase), and then one with the name "WhereRefBind" and the filename of the plugin’s main assembly which indicated success to load it from the specified path.

    However, I think this is not related to my problem. The host app uses other xml files which tell it where to load the plugins from – and then it uses LoadFrom (apparently this causes the WhereRefBind names all over).

    My Reference.dll showed up in only in failure

    cases (one for the older version and one for the new).

    Anyway, I don’t really know what I did (maybe it was changing to the Debug config and compiling and changing back to Release? Don’t remember) – but the next time I loaded the host app it loaded my plugins each with its own version of the Reference.dll.

    I appreciate your help though! 🙂

  5. Rogerio's says:

    The methods Assembly.Load and Assembly.LoadFrom are very handy to load assemblies on-demand, but, you

  6. The methods Assembly.Load and Assembly.LoadFrom are very handy to load assemblies on-demand, but, you

  7. Tinnitus says:

    Os métodos Assembly.Load e Assembly.LoadFrom são bem práticos para carregar assemblies

Skip to main content