Chris
Chris

Reputation: 4231

How to avoid repeated constant string in .NET AssemblyVersion and AssemblyFileVersion

In a C# project, we increment versions manually and have a top-level file MyAssemblyInfo.cs containing

[assembly: AssemblyVersion("31.1.13")]
[assembly: AssemblyFileVersion("31.1.13")]
[assembly: AssemblyInformationalVersion("31.1.13-V1.0.0")]

I'd like to avoid repeating the version. For example, with the C preprocessor, one could write this as

#define VERSION "31.1.13"
[assembly: AssemblyVersion(VERSION)]
[assembly: AssemblyFileVersion(VERSION)]
[assembly: AssemblyInformationalVersion(VERSION "-V1.0.0")]

Is there a way to achieve this in C# without using any external tools?

Upvotes: 2

Views: 503

Answers (2)

pinkfloydx33
pinkfloydx33

Reputation: 12749

The short answer to your question is no you cannot use pre-processor directives in this manner. One work-around is stated in the other answer and involves defining a constant. This would be perhaps the only solution for old-style projects.

If you are using the SDK-style project format however, AssemblyInfo attributes can be set in the project file. The following properties correspond to the attributes defined above:

  • InformationalVersion -> AssemblyInformationalAttribute
  • AssemblyVersion -> AssemblyVersion
  • FileVersion -> AssemblyFileVersion
  • Version -> Can map to any/all of the above if they are omitted
    • Has special logic to remove suffix patterns when setting File/Assembly version

All other Assembly attributes can be set via properties so long as GenerateAssemblyInfo is true. This requires you to remove your AssemblyInfo.cs file to prevent duplication of those attributes.*

The way I have typically solved this is to define my own set of version-related properties in my project file (see notes below for why). For example, you might have the following:

<PropertyGroup>
   <GenerateAssemblyInfo>true</GenerateAssemblyInfo>
   <BaseVersion>31.1.13</BaseVersion>
   <InfoSuffix>v1.0.0</InfoSuffix>
</PropertyGroup>
<PropertyGroup>
   <!-- note: "-v1" is invalid in an Assembly Version; I assumed you meant this on the Informational one -->
   <InformationalVersion>$(BaseVersion)-$(InfoSuffix)</InformationalVersion>
   <AssemblyVersion>$(BaseVersion)</AssemblyVersion>
   <FileVersion>$(BaseVersion)</FileVersion>
</PropertyGroup>

You could pass any of these properties on the command line to MSBuild or dotnet build if you wanted to explicitly override them:

dotnet build -p:InfoSuffix=v2.0+1234
# alternatively, specify the MSBuild properties directly
dotnet build -p:FileVersion=1.2.3.4 -p:InformationalVersion=5.6.7.8

If you have multiple projects you could set all of these properties inside of a Directory.Build.props file so that they apply to all of your projects at once.

Some Notes

First, if you are using the Directory.Build.props mechanism and running any sort of post-processing tasks or something like SourceLink (which appends info to the Informational version) you will need to move the second property group into a Directory.Build.targets file instead. You'd also need to do this if you wanted to pass the properties explicitly to other tooling, such as dotnet pack.

Second, MSBuild has a series of other version-related properties**. These include (but are not limited to):

  • SourceRevisionId - appended to the Informational version (our InfoSuffix)
  • VersionPrefix - A Base version
  • VersionSuffix - Sets prerelease label
  • PackageVersion - generates nuget version

You can use these in combination with those specified above instead. You can even pass them as properties on the command-line if you wanted to override the values in the project/props/targets files.

Now you might wonder why I bother defining my own properties instead of using the built-in ones. The reason is that MSBuild has some strange and sometimes unexpected behavior depending on how combinations of these properties are set. Anecdotally, I noticed different behavior depending on which values I was setting and whether I was building in VS, on the command line, or using dotnet pack. It is because of this I prefer defining my own properties and then using them to explicitly set the others. It also allowed me to use conditional MSBuild logic to set certain parts of the version easier. Though I do admit, your mileage may vary.

* If you want to keep the AssemblyInfo.cs file for other attributes, you'd have to disable their automatic generation by leveraging the individual GenerateX MSBuild properties.

** For a good explanation of some of these properties, see this blog post.

Upvotes: 1

NIKER
NIKER

Reputation: 474

[assembly: AssemblyFileVersion(AppVersion.Version)]
[assembly: AssemblyInformationalVersion(AppVersion.Version)]
// you can use + here but the format you use shows as invalid version for me
[assembly: AssemblyVersion(AppVersion.Version)] 

// this must be at the end of the global declarations
internal class AppVersion
{
    public const string Version = "31.1.13";
}

Upvotes: 5

Related Questions