43

I would like to be able to specify the version number for all assemblies to be generated during a build as a MSBuild command argument like this:

MSBuild.exe /p:version=5.4.3.0 

I have looked over AssemblyInfoTask but it does not seem to me like a good solution in this case.

Jeroen
  • 60,696
  • 40
  • 206
  • 339
Radu M.
  • 1,271
  • 2
  • 14
  • 19
  • Why is the AssemblyInfo task not suitable for you? It's purpose *is* to set assembly information, including the version number (AssemblyVersion) attribute. – DaveE Dec 09 '11 at 17:57
  • The version number need to be set up based on some external rules not on some rules that can be built-in using AssemblyInfoTask. Basically I want the command line argument to become the version number. – Radu M. Dec 09 '11 at 21:29
  • I used https://www.nuget.org/packages/MSBuild.AssemblyVersion/ package to achieve this. – GKalnytskyi Oct 21 '19 at 00:48

5 Answers5

46

For SDK-style projects that are built using dotnet.exe, assembly version attributes are generated automatically, so you can use /p:Version=5.4.3.0 right out of the box.

If you use the old project format, you need to add the following BeforeBuild step to your .csproj file. No need to use extra .targets and extension packs, because MSBuild already has a nice built-in task which does most of the stuff:

<Target Name="BeforeBuild">
  <ItemGroup>
    <AssemblyAttributes Include="AssemblyVersion">
      <_Parameter1>$(Version)</_Parameter1>
    </AssemblyAttributes>
  </ItemGroup>
  <MakeDir Directories="$(IntermediateOutputPath)" />
  <WriteCodeFragment Language="C#"
                     OutputFile="$(IntermediateOutputPath)Version.cs"
                     AssemblyAttributes="@(AssemblyAttributes)" />
  <ItemGroup>
    <Compile Include="$(IntermediateOutputPath)Version.cs" />
  </ItemGroup>
</Target>

Just make sure you remove the existing AssemblyVersion attribute because it will now be generated during build.

Update 7/29/2020: Michael Parker has pointed out that if you use this approach and do a build from Visual Studio, you end up with an empty version in the Version.cs file. To overcome this, I suggest defining the default Version value in your .csproj or Directory.Build.props file as follows:

<PropertyGroup>
  ...
  <Version Condition="'$(Version)' == ''">1.0.0.0</Version>
</PropertyGroup>

This will set it to 1.0.0.0 if Version wasn't specified in the command line.

Yarik
  • 1,423
  • 1
  • 14
  • 16
  • 2
    Note to self: Don't forget .Net Framework projects can also have SDK-style project files! – Gerardo Grignoli Jan 09 '20 at 01:35
  • This answer seems to leave a Version.cs with an empty version inside when you run from visual studio and not on the command line / CI. – Michael Parker Jul 29 '20 at 18:38
  • 1
    @MichaelParker thanks for pointing that out. I have updated the answer. – Yarik Jul 30 '20 at 00:55
  • 2
    `` should be specified **after** `` line as I've just learned – oleksa Aug 05 '21 at 14:49
  • You have to comment the lines `[assembly: AssemblyVersion` and `[assembly: AssemblyFileVersion` if you have a file Properties\AssemblyInfo.cs – daniol Dec 02 '21 at 09:20
  • Thanks @oleksa ! Your comment is important. – Sahitya Sep 23 '22 at 09:58
  • The in-built solution also works for .NET Framework SDK projects that are built by invoking msbuild.exe directly (using dotnet.exe isn't a requirement). I'd assume this is also true for .NET Core projects. – Andrew Sep 30 '22 at 15:12
21

I know this is an old question but Google leads me to here as top result.

I followed a simple solution in updated link (thanks Peter for the updated link). No need for extension pack.

Basically what you need to do is add a "BuildCommon.targets" files and modify your csproj file accordingly to have the version number specified in msbuild like:

msbuild.exe abc.sln /p:Configuration=Release;VersionAssembly=1.2.3.4

Hope this helps.

Jach
  • 557
  • 5
  • 12
  • Should it be AssemblyVersion? – Michael Freidgeim Oct 28 '17 at 04:10
  • 1
    @Freidgeim: that depends on how you name that command switch in the BuildCommon.targets file. that's totally up to you :) – Jach Nov 01 '17 at 10:20
  • 4
    It's 2019... and this is still the simplest solution for setting some version numbers... sigh. Microsoft, please fix this. – ebol2000 Apr 25 '19 at 16:30
  • 5
    They did, for dotnet.exe you can specify like you'd want `/p:Version=1.2.4` – CubanX May 22 '19 at 13:56
  • This worked great for me. The linked article was very informative. Only snag I hit was that in my AssemblyInfo.cs files, I have 1.0.* instead of the 1.0.0.0 that the regex was looking for. Once I corrected that, it worked like a charm. – galamdring Sep 24 '19 at 17:42
  • It seems the link is dead and I can't find a cached version. What kind of csproj modifications are needed for this solution? – TylerBrinkley Jun 28 '21 at 13:48
  • Link here: https://web.archive.org/web/20210118064331/http://www.lionhack.com/2014/02/13/msbuild-override-assembly-version/ – Peter Jul 27 '22 at 02:10
19

I use the AssemblyInfo task as you describe in your comment all the time.

  <!-- update standard assembly attribute in all projects -->
  <Target Name="BeforeBuild" >
    <Message Text="Updating AssemblyInfo to Version $(VersionNumber)"></Message>
    <Message Text="Writing to AssemblyInfo files in $(SolutionRoot)"></Message>
    <AssemblyInfo AssemblyInfoFiles="@(AssemblyInfoFiles)" 
                  AssemblyCopyright="$(AssemblyCopyright)" 
                  AssemblyVersion="$(VersionNumber)"
                  AssemblyFileVersion="$(VersionNumber)"
                  >
    </AssemblyInfo>
  </Target>

The VersionNumber value is passed from outside the MSBuild project file exactly as you describe:

  MSBuild <project_file> /p:VersionNumber=<value>;...

We use the BeforeBuild target to ensure the AssemblyInfo.cs files all get worked on before the build starts. Is this not what you want?

DaveE
  • 3,579
  • 28
  • 31
  • 2
    When I try this I get an error that says the AssemblyInfo task is not found. I googled for "AssemblyInfo task" and installed something by that name as an MSBuild extension, but that didn't work. Could you provide a link to the one you're using? – CoderDennis Oct 12 '12 at 22:25
  • @DennisPalmer , we use the task from the [MSBuild Extension Pack](http://msbuildextensionpack.codeplex.com/). Include the ...tasks file in a PropertyGroup element and you should be good to go. – DaveE Oct 15 '12 at 19:45
  • installing that extension pack did not help, I still have the error so I opened SO question here http://stackoverflow.com/questions/13090933/assemblyinfo-not-found-and-msbuild-extension-pack-installed – Dean Hiller Oct 26 '12 at 16:40
  • 3
    could one of you please provide a minimal working example on GitHub or so? – dfsg76 Apr 09 '17 at 07:10
  • Which Tasks file is needed? Do we just add that to our solution? – FlappySocks Jul 14 '18 at 14:36
  • @FlappySocks this is an abbreviated version of what we do in our build process: ` C:\Program Files (x86)\MSBuild\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks ... ... rest of build process ` – DaveE Jul 16 '18 at 18:52
7

The top answer is great, but I needed to make a few adjustments. We have a solution containing a mix of SDK and non-SDK projects. Further we also use AspNetCompileMerge for pre-compiling ASP.NET MVC 5 views. Using the property name AssemblyAttributes causes the target of GenerateAssemblyInfo from AspNetCompileMerge.targets to be executed and failing. So I finally arrived on the following target that is shared by the whole solution through Directory.Build.props:

<PropertyGroup>
    <Version Condition="'$(Version)' == ''">1.0.0.0</Version>
    <AssemblyVersion Condition="'$(AssemblyVersion)' == ''">$(Version.Split('-')[0])</AssemblyVersion>
    <FileVersion Condition="'$(FileVersion)' == ''">$(Version.Split('-')[0])</FileVersion>
    <InformationalVersion Condition="'$(InformationalVersion)' == ''">$(Version)</InformationalVersion>
</PropertyGroup>
<Target Name="NonSdkGenerateAssemblyInfo" DependsOnTargets="PrepareForBuild" BeforeTargets="BeforeBuild" Condition="('$(UsingMicrosoftNETSdk)' != 'True' And '$(GenerateAssemblyInfo)' != 'False')">
    <ItemGroup>
        <NonSdkAssemblyAttributes Include="AssemblyVersion">
            <_Parameter1>$(AssemblyVersion)</_Parameter1>
        </NonSdkAssemblyAttributes>
        <NonSdkAssemblyAttributes Include="AssemblyFileVersion">
            <_Parameter1>$(FileVersion)</_Parameter1>
        </NonSdkAssemblyAttributes>
        <NonSdkAssemblyAttributes Include="AssemblyInformationalVersion">
            <_Parameter1>$(InformationalVersion)</_Parameter1>
        </NonSdkAssemblyAttributes>
    </ItemGroup>
    <WriteCodeFragment AssemblyAttributes="@(NonSdkAssemblyAttributes)"
                       Language="C#"
                       OutputDirectory="$(IntermediateOutputPath)"
                       OutputFile="AssemblyInfo.cs">
        <Output TaskParameter="OutputFile" ItemName="Compile" />
        <Output TaskParameter="OutputFile" ItemName="FileWrites" />
    </WriteCodeFragment>
</Target>

You can add additional attributes if needed. The default version number is 1.0.0.0 and you can specify additional version numbers on the command line, mimicking SDK-behaviour:

  • AssemblyVersion and FileVersion default to the value of $(Version) without the suffix. For example, if $(Version) is 1.2.3-beta.4, then the value would be 1.2.3.
  • InformationalVersion defaults to the value of $(Version).
Bouke
  • 11,768
  • 7
  • 68
  • 102
  • this worked great! tried so many solutions w/ and w/o extensions to do this - use a single version in the CLI and have it handle setting them all. cheers! – Poat Sep 28 '22 at 16:43
1

The top answer is indeed good. In addition here's a couple of clarifications/suggestions that might prove useful (and perhaps obvious from the above postings) to avoid any custom targets, BeforeBuild, etc.

  • For SDK projects (i.e. no AssemblyInfo.cs): /p:Version='1.0.0-patch' will also work for msbuild.exe (and dotnet.exe of course) without any csproj changes. Useful for example when targetting v3 Wix setup projects that still don't support dotnet.exe. Plus you can assign $AssemblyVersion and $FileVersion to empty values since $Version will assign them automatically.
  • For non-SDK projects, instead of modifying csproj with custom targets, BeforeBuild, etc then it might just be simpler/quicker to upgrade them to SDK style projects, i.e. remove the obsolete AssemblyInfo.cs usage. Refer migrating projects.
stoj
  • 1,116
  • 1
  • 14
  • 25