57

Simple question... is there a way to change the Assembly Version of a compiled .NET assembly?

I'd actually be fine with a way to change the Assembly File Version.

Mike
  • 1,445
  • 1
  • 11
  • 14

7 Answers7

45

You can use ILMerge:

ILMerge.exe Foo.dll /ver:1.2.3.4 /out:Foo2.dll

A valid reason to do this is to increment the assembly version in a build in you find breaking changes (using NDepend for example). That way if there are no breaking changes the assembly version stays the same, and you can patch released builds easily.

We always increment the file version, and that reflects the build number.

MarkGr
  • 1,048
  • 11
  • 13
  • 1
    Unless the assembly is wpf or silverlight? – Ed Guiness Apr 28 '11 at 08:37
  • Another possible scenario I have in mind is that you build an alpha version and you want to elevate to beta, release candidate, and then release without a full rebuild. If build and test takes a little while (20 minutes), this would save a lot of time elevating through the different stages, and it would ensure the binaries you tested are the ones you ship. – jpmc26 Dec 15 '15 at 16:52
  • Just needed this for debugging. Had a resource dll that didn't match it's corresponding dll. – dudeNumber4 Aug 19 '16 at 13:01
  • Upldated link to IlMerge seems to be https://github.com/dotnet/ILMerge – Jari Turkia Dec 20 '19 at 08:43
16

Old topic but here are my 5 dimes...

  1. Disassemble

    ildasm my.exe /output:my.il /metadata

  2. Edit my.il to change version information. There are several places to look into:

    • major:minor:revision:build - usually one occurrence
    • major.minor.revision.build - several occurrences. The string is found in the comment section after the actual line. The version is a hexadecimal value in a byte array. Example:

.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 35 2E 31 2E 33 2E 30 00 00 ) // ...5.1.3.0..

  1. Edit my.res to change version information. Double click and edit with visual studio. Pretty straight forward procedure.

  2. Assemble

    ilasm my.il /res:my.res

Christian
  • 9,914
  • 6
  • 45
  • 52
  • 2
    While ILMerge as mentioned in the currently most upvoted answer did not work for me, this did! Thank you! :-) – Christian Jul 11 '16 at 15:39
  • 1
    It doesn't work for DLLs. The error I get on step 4 is Creating PE file Error: No entry point declared for executable Could not create output file, error code=0x80004005 ***** FAILURE ***** – Rahul Misra Oct 13 '16 at 09:58
  • 4
    I just needed to add a /dll switch on step 4. ilasm my.il /res:my.res /dll – Rahul Misra Oct 13 '16 at 10:04
  • 2
    Unlike ILMerge, this solution also works for .Net Core assemblies. Thanks! – user2363676 Dec 19 '18 at 16:52
8

Why do you want to do this? If it's so that another application can use it, you might want to look into assembly binding redirection instead.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 4
    For deployment, we update the AssemblyInfo files and do a full rebuild, but that is getting too heavy, so we're moving to an incremental build. The problem is determining which AssemblyInfo's to update so right now we're not updating the version on the incrementals. – Mike Dec 29 '08 at 17:54
  • So, current possible solution I'm looking at is updating the Assembly File Version post-build so that everybody knows which build of the code you're looking at. – Mike Dec 29 '08 at 17:56
  • You want to use an incremental build for *deployment*? Yikes. How long does your build take, and how often do you deploy? I personally wouldn't be comfortable with that - I'd want a clean, full build (and test run) for deployment. Much easier to reproduce that way. – Jon Skeet Dec 29 '08 at 17:58
  • 1
    No, deployment will still be a full clean build. Please, give me some credit! Incremental is just for the continuous internal build. Problem becomes people don't know which build they're looking at/testing unless it's a full clean build with updated AssemblyInfo. – Mike Dec 29 '08 at 18:08
  • 2
    If it's only for internal purposes can you just include a version.txt file? Low tech but simple :) – Jon Skeet Dec 29 '08 at 18:18
  • 1
    You may want to edit some of this commentary into the original question, might be helpful. – GWLlosa Dec 29 '08 at 18:18
  • 1
    Our build is the same for both deployment and internal testing. That way we will never risk testing something that we aren't shipping out, or more importantly, shipping out something other than what we tested. That way we only have one place where the version numbers are updated. – Lasse V. Karlsen Dec 30 '08 at 14:19
  • Also, FYI, as far as I can tell, assembly binding redirection only works against strongly named assemblies. – Mafu Josh Jun 22 '11 at 19:59
4

If you have formal testing and source control, the process becomes fairly straightforward. It starts with an understanding of who can change the diferent number segments of the version, and when. .net assemblies have 4 number segments (i.e. 1.0.0.1).

The first segment contains the Major Version number. This is set by upper management and indicates a major change in the UI or in the platform of the app. This should always be same number between the assembly version and the file version.

The second segment contains the Minor Version number, also known as the Feature Release number. This is set by Project Management and indicates that new features have been added to the app. This should always be same number between the assembly version and the file version.

The third segment contains the Build number. This is set by the testing group and indicates that the app is ready to be deployed. It is changed before bug fixes are released. When releasing a new build, testing resets the fourth segment to 0. This can be the same number between the assembly version and the file version, but is usually left at 0 for the assembly version to simplify patching existing deployments.

The fourth segment contains the Revision number. This set by the development group whenever they check new code into source control. This number would be included in the file version of the compiled DLL, but not in the assembly version.

I have found that this helps deployers, testers and developers keep track of the latest versions without stepping on each others toes. Unfortunatley, I have also worked with companies that used a static versioning system so that nobody really knew what the latest, best assembly was.

Bernard Vander Beken
  • 4,848
  • 5
  • 54
  • 76
4

It sounds like your process is heavy because you have to update multiple AssemblyInfo files. Have you considered sharing the same AssemblyInfo file between projects? Derik Whittaker gives a good example on how to do this.

Once you have a single file, you could then go the extra distance by having a build process update your single AssemblyInfo version using MSBuild or NAnt.

2

VerPatch, as referenced in this answer, is simple and effective.

Community
  • 1
  • 1
Neil
  • 7,227
  • 5
  • 42
  • 43
0

Its strange folks have missed Resource Hacker. It is specially made for hacking file resources. So it will also help you edit assembly information including File Version.

using System;
using System.Windows.Forms;
using System.Diagnostics;

public class rh
{
    public static void Main()
    {
        Assembly_Changer("file_path.exe");
    }
    
    private static string rc()
    {
        string FileVersion = "6,8,0,1";
        return "1 VERSIONINFO"
        + "\n FILEVERSION " + FileVersion
        + "\n PRODUCTVERSION 0,0,0,0" 
        + "\n FILEOS 0x4"
        + "\n FILETYPE 0x1"
        + "\n {BLOCK \"StringFileInfo\"{BLOCK \"000004b0\"{}}BLOCK \"VarFileInfo\"{VALUE \"Translation\", 0x0000 0x04B0}}";
    }

    public static void Assembly_Changer(string exe)
    {
        System.IO.File.WriteAllText("details.rc", rc());
        process("reshacker.exe", "-open details.rc -save resources.res -action compile -log NUL");
        process("reshacker.exe", "-open \"" + exe + "\" -resource resources.res -save \"" + exe + "\" -action addoverwrite -mask \"Version info\"");
    }

    public static bool process(string filename, string args)
    {
        using (Process process = new Process())
        {
            process.StartInfo.FileName = filename;
            process.StartInfo.Arguments = args;
            process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            process.Start();
            process.WaitForExit();
        }
        return true;
    }   
}
Sorry IwontTell
  • 466
  • 10
  • 29