While working in .NET, I came across various scenarios in which I had to manually load assemblies into my application. This gave me an opportunity to learn about two well known methods of Assembly Loading
Assembly.LoadFrom() and one less known method
Ok... let me ask you some questions:
- Can I load multiple versions of the same assembly in a particular AppDomain?
- Can I have two copies of the same assembly, if yes which loaded assembly will have priority?
- The last one.... Can I have n copies of an identical assembly loaded in an application domain? How will the system behave in that case?
I hope some of you may find these questions silly and some may be thinking how does that matter.
Let me first explain what all
Assembly.Load****() method does before I start answering the questions.
Assembly.load takes the fully qualified assembly name and uses the .NET defined algorithm to search for an assembly. You can find more details here regarding How Runtime Locates Assemblies. Using this method, you can load assembly of a single version only once.
Assembly.LoadFrom takes the full path of the assembly and if you call this method, it will load assembly into the application domain provided it has not been loaded from the same path by this or any of the other methods. The beauty of this is that it does not load same assembly again from any other path if it has been loaded by this method before.
For example, let's say I have MyAssembly.dll at the following path:
- Application output path, say C:\MyApplication\bin\Debug
- At path C:\MyApplication\ExternalAssemblies
- AT path C:\TestAssemblyLoading
When the application will run, this assembly will automatically be loaded from the first path. Now if I try to load the assembly using
Assembly.LoadFrom from path 1, it will not be loaded. but if I do so using path 2, the assembly will be loaded again. but after that, if I try to load assembly from path 3 using
Assembly.LoadFrom, it will not be loaded now as it has already been loaded from path 2.
Assembly.LoadFrom allows assembly to be loaded once from a path from which it has not been loaded yet.
So, using the above two methods, you can load an assembly at least two times even if everything in those assemblies is the same.
This is the most lazy method you can say. It tries to minimise its work and does not look for anything. If you call this method, it will load the assembly every time in the
AppDomain. No no, don't think it is that lazy if you give this method same location again it will not load the assembly again from same path but it will do if path is different. So to get an assembly loaded 10 times, you need to have 10 different locations where the same assembly is present.
As a thumb rule, you should always rely on
Assembly.Load in case you know the path of assembly is not in .NET search path use
Assembly.LoadFrom() but even in that case, check using
AppDomain.GetAssemblies() method if the assembly is already loaded before into the
For a long time, I was confused as to why .NET is providing a silly method like
Assembly.LoadFile() but later I came to know that there may be a scenario in which the architecture of product may be such that it is loading assembly dynamically from the various locations based on the requirement but the versions are same in all folders.
For example, let's say that I am making an international product which has resources in an assembly which is present in the folder named after the country. For simplicity purposes, I want to keep the version and assembly name the same for all these assemblies. Now the server is present in one country and the requests are coming from all over the world. The server part needs to load all the assemblies with the same version and name based on from which country the request is coming. Application is retrieving resource text using reflection by loading the assembly. Now to achieve this, we have to use
Assembly.LoadFile so that we can load all the assemblies in spite of the fact that their version and name is same.
Now I hope you must have got the answers of all the questions I asked at the start of this topic. Still something I want to tell you may be left ...Let's see.
Answer 1. This is obviously yes, any of the above methods will do that.
Answer 2. The answer is yes, but the explanation of the other part is tricky.
Look at the below code.
I have an assembly TestAssembly.dll in which I have in two folders, f1 and f2. I am trying to load assemblies dynamically taking advantage of
Now look at the last line. This line will fail with the error.
[A]TestAssembly.TestClass cannot be cast to
[B]TestAssembly.TestClass. Type A originates from 'TestAssembly, Version=18.104.22.168,
Culture=neutral, PublicKeyToken=null' in the context 'LoadNeither'
at location 'C:\Samples\AssemblyLoading\MultipleAssemblyLoading\f2\TestAssembly.dll'.
Type B originates from 'TestAssembly,
Version=22.214.171.124, Culture=neutral, PublicKeyToken=null'
in the context 'Default' at location
To find the reason for this, let's look at the variable
QuickWatch window. See the result below:
TestAssembly has been loaded three times. Once because the project has a reference to it and other two we loaded by our code. Now when we try to cast "
TestClass which is a type of this assembly, the compiler will throw an error because the type belongs to assembly loaded in loop and we are trying to cast it into the type which is coming from the assembly referenced into the project directly . We know they are the same but the compiler doesn't (a common mistake, isn't it ).
We need to take a precaution while using this type of code when multiple assemblies of the same version have been loaded. In a small code I wrote, it is very easy to find the problem but in a bigger system, it can be cumbersome.
Answer 3. Obviously now you know the answer is yes and the behaviour of the system will be the same as I explained above.