We have a large solution with about 30 projects. We also have some common code utilities and as part of that utility class we have included a GetAssemblyVersionInfo method that returns the version info of that assembly. However, we want to get the Assembly Version Info of the assembly for the project not the utility DLL. Is there any way of having a utility function that returns the version info of another assembly based on execution and not passing around filenames?
EDIT:
For those who are curious, I solved it using:
System.Reflection.Assembly.GetCallingAssembly().GetName().Version
If you have the assembly name, you can dynamically load it into the current AppDomain to retrieve the version info.
Assembly.LoadFrom(string.Format("{0}.dll", "assemblyshortname")).GetName().Version
I think you should use GetEntryAssembly() instead of GetCallingAssembly().
Related
I'm working on a utility that reports the version number from a .net assembly, given its path. It uses assy = System.Reflection.Assembly.LoadFrom(path) to load the assembly, then parses assy.GetName.ToString() to learn the version number.
This works fine, as long as I don't try to load 2 different files with the same assembly name in the same invocation of the program. If I do that, LoadFrom() always returns the same Assembly object, even if the files are actually different versions.
This is documented behavior, see the "Remarks" in https://msdn.microsoft.com/en-us/library/1009fa28(v=vs.80).aspx
The utility needs to run with .Net 2.0 under Windows CE; it's an industrial application running on a Symbol (now Zebra) MT2000 handheld scanner. This means that I don't have the choice to use Load() or LoadFile().
The obvious workaround is to invoke the utility twice and compare the results, but that's inconvenient for several reasons. Anybody have any better ideas?
You can try using the AssemblyName.GetAssemblyNamemethod, which doesn't Load the Assembly but causes the file to be opened and closed. More details here
AssemblyName assemblyName = AssemblyName.GetAssemblyName("YourExe.exe");
var versionOfAssembly = assemblyName.Version;
If you only need to get the name of the assembly, you can use method ReflectionOnlyLoadFrom. This method loads distinct assemblies even if they have the same assembly name.
var assm = System.Reflection.Assembly.ReflectionOnlyLoadFrom(path);
var name = assm.GetName().ToString();
How can I use different dll's (other Version) with the same name in one directory?
For Example, LibA (ExternalLib.dll) has Version 1 and LibB (ExternalLib.dll) has Version 2.
I'm deploying all my programs to the same directory (this is our companys standard and I can't change this fact). The problem is if ProgramB which is using the LibB is deployed in the directory where ProgramA is using the LibA then ProgrammA would not longer work.
For my own Libs I use a Major-Version-Number (.01, .02) if there are big changes. But the Lib I'm using is an external Lib and each version of it requires different licensing-keys (which are handled by the programs itself).
I tried to rename the external libs from "ExternalLib.dll" to "ExternalLib.v1.dll" and "ExternalLib.v2.dll", but when I run my fresh compiled programm it throws an exception that says "ExternalLib.dll could not be found". The reference in my project is set to "ExternalLib.v1.dll" and compilation works fine.
Any ideas / suggestions to handle different assembly versions in the same directory?
Unfortunately, the filename of the DLL file has very little do do with how .Net is loading these types. The actual name is written into the meta data of the assembly as part of the compilation process. So at runtime, it will be probing for ExternalLib.dll regardless of what you renamed the file to. The usual way to fix this is to install to the GAC and use Strong Naming to reference the specific version.
Given you may not be able to do this, there are 4 things you could try:
Ask the vendor to produce version specific DLL's for you. They could compile such that the version name is part of the filename and included in the assembly manifest. This would be the simplest solution for you.
Handle the AssemblyResolve event and manually try and use Assembly.Load to point at the file you want such that you can specify specifically which dll to use. See http://support.microsoft.com/kb/837908 for more information, but effectively you'll be using Assembly.LoadFrom(specific_path) to choose the file where the code will load from.
If possible, you might also be able to use ildasm.exe to decompile the dll's to Intermediate Language (IL), then use ilasm.exe to recompile it to a new dll name. You would then reference this new DLL name in your project.
If the assembly is not signed, then you may be able to edit the manifest yourself; you can either use a compatible binary editor or possibly MT.exe.
I'm using AppDomain.CreateInstanceFromAndUnwrap() to create an object in a different AppDomain. I couldn't get it to work because it kept throwing the following error at me:
Could not load file or assembly 'COMon, Version=2.0.4960.27874, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The module was expected to contain an assembly manifest.
However, I found that it is because it tries to load my DLL (which has the same name as my .NET assembly).
This is how I call the method:
_script = (Script)_appDomain.CreateInstanceFromAndUnwrap(Assembly.GetExecutingAssembly().Location, "COMon.Scripting.Script");
It works fine as long as there isn't a native DLL file with the same name as my .NET assembly. Why does this happen when I'm passing it the full path and filename of my .NET assembly?
when I'm passing it the full path and filename of my .NET assembly?
That's not how the method works. The first argument is the display name of the assembly. It is not a file name. The MSDN article recommends that you take a look at Assembly.FullName to learn more about display names.
So the normal CLR search rules will be in effect for finding the assembly. It will look in the GAC first, then in the probing path for the AppDomain. With a quirk that you didn't count on, the CLR does not pay attention to the filename extension for a file. The display name for an assembly doesn't specify it. So it considers an EXE and a DLL equivalent. Something you can see back in the trace for Fuslogvw.exe, the utility you always want to use when you have trouble like this. And in other places, adding a reference to an EXE works fine for example.
So it finds COMon.exe and that's a kaboom, it is not a managed assembly.
It isn't that clear what the proper workaround might be in your case, other than simply renaming the assembly. When you tinker with AppDomains then you typically also want to use AppDomainSetup and set the ApplicationBase or PrivateBinPath property.
After reading through the MSDN article How the Runtime Locates Assemblies and also reading this, I am still unsure about how weakly named assemblies are resolved at runtime.
Eg. if I have a reference to some dll file in my project, I compile and deploy, will it pick up a new version of the referenced dll file if I just replace the old one which was actually referenced at compile time? Does it matter if the reference in the project file specifies the version etc. of the referenced assembly?
Any enlightenment welcome
If the assembly is not found in the GAC then the CLR will search for it in the "probing path". Which by default is only the directory that contains the EXE. It only looks for a match on the assembly name and will stop searching on the first match.
It then checks the [AssemblyVersion] number. If it doesn't match you'll get an exception, it won't keep looking for another assembly with the same name. Whenever you have resolution trouble, you'll want to use the Fuslogvw.exe utility. It shows you exactly where the CLR looked and what went wrong.
The best place that I've found to learn about this is in Grimes Fusion Workshop as can be found here. It is very comprehensive while still easy to understand.
The answer to your questions is yes as long as long as you have Specific Version set to False in the properties for the reference to the assembly.
If version is not mentioned it will pick up the reference, if the version is mentioned it will try to find and load the assembly matching the signature with version mentioned. if not found it will throw an exception. To resolve this you can do assembly binding redirection.
I have a C# solution, which references a dll I created from a different C# solution.
It is easy enough to determine my solution's product version with Application.ProductVersion. However, what I really need is a way to determine the file version of the exe and the dll separately, within my program. I want to display the dll and exe's file versions in my About dialog. What would the code look like to do this?
The simplest way is if you know a type in the referenced assembly:
AssemblyName name = typeof(MyCompany.MyLibrary.SomeType).Assembly.GetName();
Assembly.GetName returns an AssemblyName which has a Version property indicating the version of the assembly.
Alternatively, you can get the assembly names of all assemblies referenced by the executing assembly (i.e., the .exe):
AssemblyName[] names = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
Perhaps the easiest solution is this:
var version = Assembly.GetAssembly(typeof(SomeType)).GetName().Version;
where SomeType is a type you know for sure that is defined in that particular assembly. You can then call .ToString() on this version object or look at its properties.
Of course, this will blow up in a huge fireball the moment you move your type into another assembly. If this is a possibility, you will need a more robust way to find the assembly object. Let me know if this is the case.
The AssemblyInfo class has all this information, so you just need to get a reference to the assembly in your code. For example:
Assembly.GetExecutingAssembly.GetName.Version.ToString()
You can get the other assemblies in the project in various ways, for example
var assemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies();