Load Assembly without culture and version - c#

I know that recommended way of loading assemblies is:
Assembly SampleAssembly = Assembly.Load
("SampleAssembly, Version=1.0.2004.0, Culture=neutral, PublicKeyToken=8744b20f8da049e3")
But, what if I don't know which version of assembly exists in GAC (for example NpSql or MySql.Data can have different versions in different machines)?
Then I might want to load it without specifying version, culture and public key token.
Is that possible? (I know about LoadWithPartialName but it is now obsolete).

It seems we can use Assembly.Load(AssemblyName) but it is not recommended way to do it.

Related

Enforce a specific version of a third-party assembly

I have an application that relies on a set of third-party DLLs, version v1.1. In order to use them, I reference the main one, which is found somewhere under the Program Files folder. This library uses the other ones, installed in the GAC.
A new version of the third-party DLLs is released, v1.2. The DLL in the Program Files folder is replaced by the new version; in the GAC, both versions co-exist.
The problem is to get the application (compiled with DLLs v1.1) to work when v1.2 is installed, without re-compiling it, and without changing the app.exe.config file.
I am the maintainer of the DLLs; additional constraints are that only the latest version of the DLL is installed in Program Files, and other DLLs are all installed in the GAC (all versions are kept).
My problem is that the application starts, but eventually I get an error because of incompatibilities between types:
Unhandled Exception: System.InvalidCastException:
[A]ThirdParty.User cannot be cast to [B]ThirdParty.User.
Type A originates from 'ThirdParty, Version=1.2.0.0, Culture=neutral, PublicKeyToken=XXXX'
in the context 'Default' at location 'C:\Windows\Microsoft.Net\assembly\GAC_32\ThirdParty\v4.0_1.2.0.0__XXXX\ThirdParty.dll'.
Type B originates from 'ThirdParty, Version=1.1.0.0, Culture=neutral, PublicKeyToken=XXXX'
in the context 'Default' at location 'C:\Windows\Microsoft.Net\assembly\GAC_32\ThirdPart\v4.0_1.1.0.0__XXXX\ThirdParty.dll'.
I am not sure to understand how the v1.2 DLL is chosen, I am guessing that the path to the DLL is stored in the application, which in turn decides to use the DLLs in the GAC for this version? I am testing on a system different from the one used for compiling, but the DLLs are located in the same location. My understanding from the documentation is that the v1.1 version in the GAC should be chosen, not v1.2.
Where is my mistake? How can I fix it?
Thanks,
I found a solution in my specific case, and re-reading my question I realize I did not mention that my initial DLL does rely on a PowerShell instance. Which is where I worked around my problem. In my DLL, I load a specific version if the DLL that is present in the GAC, and load it in my PowerShell instance:
var assembly = Assembly.Load("ThirdParty, Version=1.1.0.0, Culture=neutral, PublicKeyToken=XXXX");
var ps = PowerShell.Create();
ps.Commands.AddCommand("Import-Module").AddParameter("-Assembly", assembly);
ps.Invoke();

Set the Assembly Version and get it by reflection - all the time version 1.0.0.0?

I had a problem with setting properly the Assembly version and then obtaining it by the reflection. I found a workaround, but I am still curious why it behaves like this...
I have a Class Library project, I am loading it and reading the version by following code:
var assembly = Assembly.LoadFrom(assemblyName);
var version= assembly.GetName().Version;
And I get a good result:
assembly {AssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
version "1.0.0.0"
But now I have changed in the Class Library project the Assembly version and File version fields to the value of 2.0.0.0. I have compiled it and I have run IL DASM to compare both libraries.
Everywhere in IL DASM, i.e. in Main Window, in Manifest, in Metainfo I have seen that my new library have version 2.0.0.0 and the pervious library have 1.0.0.0, so I was happy that everything was correct.
But then I went back to my application, I have loaded the assembly with version 2.0.0.0, and this is the result:
assembly {AssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null}
version "1.0.0.0"
So the reflection does not return to me the good version value.
The workaround is to use the FileVersionInfo class:
FileVersionInfo.GetVersionInfo(assemblyName).FileVersion;
Now I get the proper result.
My questions are: what else I need to change in my Class Library Project to be able to retrieve a good version by the reflection mechanism? Why IL DASM is showing a proper version and reflection is not? I always thought that IL DASM under the hood utilize the reflection, but now it seems to me s
Thank you for all answers.
OK I have managed to solve it. The problem was with the loading method from the Assembly class.
I was using the Assembly.LoadFrom with the full path to the DLL as argument. I have realized that when I was loading my library with version 2.0.0.0 the Assembly.LoadFrom was returning my first library, I have verified it by the CodeBase property which was pointing to the location of library version 1.0.0.0 and not 2.0.0.0.
I have change my loading code to Assembly.LoadFile, now it is working properly.
var assembly = Assembly.LoadFile(assemblyName);

Making calls to different version of different assembly

I have 2 versions of same dlls. Say named, Test.dll. I want to call 2 dlls from my console application.
I tried to use Extern alias. But it is calling new dll. I am calling these 2 dlls from my DAL class.
Any help would be appreciated.
Thanks,
This is not the default way of how you do things in .net, therefore coding will not be easy in such a manner. As #Johnathon Reinhart says in his answer, you will have to use Assembly.Load (by passing the fully qualified assembly name to the function).
Like this:
Assembly asmOld = Assembly.Load("MyAssembl, Version=1.0.0.1, Culture=neutral, PublicKeyToken=ab1234567defabc1");
Assembly asmNew = Assembly.Load("MyAssembl, Version=2.0.0.1, Culture=neutral, PublicKeyToken=ab1234567defabc1")
Moreover, you will have to keep reference to both assemblies and then use Assembly.CreateInstance to create instances of the types you need. After that, you will have to call members using reflection (something like this). Like this:
Ojbect objOld = asmOld.CreateInstance("MyApp.Namespace.Classname");
Ojbect objNew = asmNew.CreateInstance("MyApp.Namespace.Classname");
objOld.GetType().InvokeMember("TestMethod", BindingFlags.InvokeMethod,null,obj,null);
objNew.GetType().InvokeMember("TestMethod", BindingFlags.InvokeMethod,null,obj,null);
To improve your code writing, you could use the LateCall from Microsoft.VisualBasic.CompilerServices to work with your objects. There is a nice wrapper for that by Andy Adinborough - http://andy.edinborough.org/Use-Late-Binding-in-C-Now-without-NET-4-0
I'm assuming that these DLLs are .NET assemblies, and not just standard C DLLs.
If so, I think you can specifically load the assembly with the static Assembly.LoadFrom(string assemblyFile). Then I think you can get a module from that assembly with Assembly.GetModule().
you can use Assembly.LoadFile or using alias
Loading Multiple Versions of same Assembly
Using different versions of the same dll in one application

Why FileNotFoundException when I Assembly.Load an assembly that is surely present?

In my Windows Azure role C# code I do the following:
Assembly.Load( "Microsoft.WindowsAzure.ServiceRuntime" );
and FileNotFoundException is thrown. The problem is an assembly with such name is present and has even loaded before the code above is run - I see a corresponding line in the debugger "Output" window and when I do:
AppDomain.CurrentDomain.GetAssemblies().Any(
assembly => assembly.FullName.StartsWith("Microsoft.WindowsAzure.ServiceRuntime"));
the result is true and if I use Where(), then SingleOrDefault() I get a reference to a corresponding Assembly object.
Why can't I load an assembly with Assembly.Load()?
That Load() call can only succeed if Microsoft.WindowsAzure.ServiceRuntime.dll is stored in your app's probing path. By default the same directory as your EXE. Problem is, it isn't stored there, it is stored in the GAC.
The point of the GAC is to act as a depository of assemblies with the same name but different [AssemblyVersion]s, culture or processor architecture. Which is the problem with your Load(), you don't specify any. There is no reasonable way that fusion can pick an assembly for you, it is apt to give you the wrong one. So it doesn't bother, even if there is only one to pick from.
Specifying the full AsssemblyName.FullName is required. Use Project + Add Reference to avoid.
You should load it with a full assembly qualified name.
From the MSDN documentation:
// You must supply a valid fully qualified assembly name.
Assembly SampleAssembly = Assembly.Load
("SampleAssembly, Version=1.0.2004.0, Culture=neutral, PublicKeyToken=8744b20f8da049e3");
The documentation for Assembly.Load says that you're meant to supply the full name for the assembly (including e.g. version information).
Using just a plain name for the assembly will fail if the assembly is normally loaded from e.g. the GAC. E.g.:
try
{
Assembly.Load("System");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.WriteLine(AppDomain.CurrentDomain.GetAssemblies().Any(
assembly => assembly.FullName.StartsWith("System")));
Console.ReadLine();
Exhibits similar behaviour.

How to correctly load PresentationFramework assembly from the GAC?

I need to dynamically get the list of Controls in the PresentationFramework assembly. For now, I can load the assembly with this piece of code:
var asmName = new AssemblyName("PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
var asm = Assembly.Load(asmName);
However, if in the future the framework is updated to higher version, the above code won't be able to pick up the new assembly. Please show me how to do it the right way. Many thanks.
I don't think that there is a way to automatically get the latest version of an assembly in the GAC, since that could lead to the whole "DLL Hell" problem all over again. Strong-named assemblies, which all assemblies in the GAC are required to be, include their version number in their name to ensure that you are loading exactly the version you expect. This will prevent a newer version of the assembly from breaking your application.
It's depreciated but you can use:
Assembly.LoadWithPartialName("PresentationFramework");

Categories