How do I get the version of an assembly without loading it?
Asked Answered
C

5

28

One small function of a large program examines assemblies in a folder and replaces out-of-date assemblies with the latest versions. To accomplish this, it needs to read the version numbers of the existing assembly files without actually loading those assemblies into the executing process.

Ceto answered 9/10, 2008 at 16:13 Comment(3)
What language are you coding in?Monkhood
@RB: Language doesn't matter, because one would be using the same classes to get the information.Foretoken
You need to make jop's or Joel's answer the correct one. I would vote them up to a million if I could. I've wanted to know how to do this for years.Salter
F
44

I found the following in this article.

using System.Reflection;
using System.IO;

...

// Get current and updated assemblies
AssemblyName currentAssemblyName = AssemblyName.GetAssemblyName(currentAssemblyPath);
AssemblyName updatedAssemblyName = AssemblyName.GetAssemblyName(updatedAssemblyPath);

// Compare both versions
if (updatedAssemblyName.Version.CompareTo(currentAssemblyName.Version) <= 0)
{
    // There's nothing to update
    return;
}

// Update older version
File.Copy(updatedAssemblyPath, currentAssemblyPath, true);
Foretoken answered 9/10, 2008 at 16:21 Comment(4)
Crap. As always for me, this doesn't work on the Compact Framework. AssemblyName is there, but AssemblyName.GetAssemblyName isn't.Salter
An older trick I used to use (for scanning through plugin assemblies) was to create a sandbox AppDomain, load them in that, and then close down the AppDomain when I was done. Not sure about CF, though.Foretoken
Won't fit here. But it relies on an object created in the new AppDoain loading the assebly, which means using AppDomain.CreateInstance(), which doesn't seem to be supported in CF. You should ask a new question, link to this one, and specify Compact Framework.Foretoken
+1, but there's just one caveat - if you're using code like this and you update your DLLs to target a new CLR (i.e. when upgrading from framework 3.5 to framework 4.0), this will produce a "This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded" error...Roa
D
14

Depending on the files, one option might be FileVersionInfo - i.e.

FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(path)
string ver = fvi.FileVersion;

The problem is that this depends on the code having the [AssemblyFileVersion] attribute, and it matching the [AssemblyVersion] attribute.

I think I'd look at the AssemblyName options suggested by others first, though.

Dugan answered 9/10, 2008 at 16:23 Comment(4)
Comparing the FileVersionInfo like this could be useful as well. An update to a library which fixes bugs but does not change the API could have the same Assembly version but should have a different file version. So in many cases the AssemblyFileVersion may be the one you want to check.Draper
Tip: Using FileVersionInfo lives in the System.Diagnostics namespace which you would need to import.Pollinate
@eithe although to be fair, you can just press ctrl+. (with the focus on an unresolved type) and the IDE will find it and add it for you... then you don't need to memorise namespacesDugan
True, @MarcGravell, but I was deploying this through rdp in a test area and only had notepad there :)Pollinate
S
9

Use AssemblyName.GetAssemblyName("assembly.dll");, then parse the name. According to MSDN:

This will only work if the file contains an assembly manifest. This method causes the file to be opened and closed, but the assembly is not added to this domain.

Semitrailer answered 9/10, 2008 at 16:21 Comment(1)
I'm trying not to think of all the hacks I've implemented trying to get a version number without loading the file. Yeesh.Salter
A
3

Just for the record: Here's how to get the file version in C#.NET Compact Framework. It's basically from OpenNETCF but quite shorter and exctacted so it can by copy'n'pasted. Hope it'll help...

public static Version GetFileVersionCe(string fileName)
{
    int handle = 0;
    int length = GetFileVersionInfoSize(fileName, ref handle);
    Version v = null;
    if (length > 0)
    {
        IntPtr buffer = System.Runtime.InteropServices.Marshal.AllocHGlobal(length);
        if (GetFileVersionInfo(fileName, handle, length, buffer))
        {
            IntPtr fixedbuffer = IntPtr.Zero;
            int fixedlen = 0;
            if (VerQueryValue(buffer, "\\", ref fixedbuffer, ref fixedlen))
            {
                byte[] fixedversioninfo = new byte[fixedlen];
                System.Runtime.InteropServices.Marshal.Copy(fixedbuffer, fixedversioninfo, 0, fixedlen);
                v = new Version(
                    BitConverter.ToInt16(fixedversioninfo, 10), 
                    BitConverter.ToInt16(fixedversioninfo,  8), 
                    BitConverter.ToInt16(fixedversioninfo, 14),
                    BitConverter.ToInt16(fixedversioninfo, 12));
            }
        }
        Marshal.FreeHGlobal(buffer);
    }
    return v;
}

[DllImport("coredll", EntryPoint = "GetFileVersionInfo", SetLastError = true)]
private static extern bool GetFileVersionInfo(string filename, int handle, int len, IntPtr buffer);
[DllImport("coredll", EntryPoint = "GetFileVersionInfoSize", SetLastError = true)]
private static extern int GetFileVersionInfoSize(string filename, ref int handle);
[DllImport("coredll", EntryPoint = "VerQueryValue", SetLastError = true)]
private static extern bool VerQueryValue(IntPtr buffer, string subblock, ref IntPtr blockbuffer, ref int len);
Ambrosio answered 13/2, 2014 at 13:18 Comment(1)
Very nice, useful indeed.Beanfeast
B
0

A .netcore update to Joel's answer, using AssemblyLoadContext:

using System.IO;
using System.Reflection;
using System.Runtime.Loader;

...

// Get current and updated assemblies
AssemblyName currentAssemblyName = AssemblyLoadContext.GetAssemblyName(currentAssemblyPath);
AssemblyName updatedAssemblyName = AssemblyLoadContext.GetAssemblyName(updatedAssemblyPath);

// Compare both versions
if (updatedAssemblyName.Version.CompareTo(currentAssemblyName.Version) <= 0)
{
    // There's nothing to update
    return;
}

// Update older version
File.Copy(updatedAssemblyPath, currentAssemblyPath, true);

I found this useful in analyzing DLLs running (and locked) by a Windows Service, a much cleaner alternative to creating a separate AppDomain.

Burgle answered 26/2, 2021 at 17:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.