Assemblies Side by Side

CLR today supports multiple versions of an assembly side by side, contrast to native loader.


In the native world, when you call LoadLibrary(“foo.dll”) multiple times, you will only get one copy of foo.dll loaded. In CLR, since the assembly name includes version number, you can issue Assembly.Load() on different versions of assembly foo, and multiple versions of assembly foo will be loaded. (Let’s ignore the binding policy here).


But assemblies side by side does not come for free.


  1. If the assembly has AppDomain/Process wide states, multiple versions of the assembly may change the states simultaneously, causing unexpected result.

  2. Types from different versions of the assembly can not be casted to each other.


The second one is the killer. You have to be very careful about expose types from the assembly, since any type could potentially be compared against a type from a different version of the same assembly, results in InvalidCastException.


Assemblies side by side works when none of the types are exposed by other assemblies, or consumers of the two versions of the assembly work independently, and never talk to each other.


Beyond those simple scenarios, it requires strict engineering and QA to make multiple versions of an assembly side by side work.


These restrictions make assemblies side by side much less useful than it sounds.

Comments (6)

  1. Anonymous says:

    "CLR today supports multiple versions of an assembly side by side, contrast to native loader."

    Huh? Then what is this all about:

  2. junfeng says:

    Isolated application and assemblies means different applications can use different assemblies. But in the same application, only one version of assemblies is allowed.

    CLR does not have this restriction.

  3. mgrier says:

    Two relevant points:

    1. For native sxs support, we took it as a basic requirement that we were not going to change all the myriad APIs which bind to objects based on names of some sort (file names, guids, whatever) and change the APIs to take additional parameters. Thus, within any context ("activation context"), bindable names have to be unique and unambiguous.

    To avoid setting false expectations, we more simply refused to allow more than one assembly into a given context with the same name. This restriction could be relaxed over time but still when someone calls CoCreateInstance() with some guid, it has to map unambiguously to exactly one COM server, so the apparent utility of loading multiple versions of the same component into a given context is pretty low since the versions would have had to change all the public bindable names (e.g. rename all the DLLs, reguid all the com servers, change all IIDs, change all progids, etc.).

    Personally I think that this is a much better solution than what CLR did in putting component identities on each type name reference. It gives us a lot more agility and the restriction to not be able to load more than one version of a component into a given context simultaneously is not much of a restriction in practice.

    2. The real problem here is that "Elvis friendly" type signatures are, in general, directly at odds with "compatibility friendly" type signatures. I think this is just life and we need to stop our hand-wringing and wailing "surely something must be done!". There have been several grand experiments in this space and basically they all failed in their grandiose plans. Either you get locked into compatibility on an API with a huge surface area or you end up breaking your clients all the time. This dilemma is exactly why we invented sxs in the first place to give some flexibility here.

  4. junfeng says:

    Thanks Mike.

    The CLR model is really no different from the native sxs model. Each type has a qualified assembly token, and the assembly token has the version number. In native sxs, the assembly token is implied by the containing manifest. The difference is really a binding policy.

    I certainly won’t argue which one is better. They are just different.

  5. One of the important facets of successful solution design is realizing that the less code you develop