Assembly Version Required

ID

csharp.assembly_version_required

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Best Practice

Language

CSharp

Tags

assembly, best_practice, dotnet, versioning

Description

Reports a .NET project that declares no assembly version: neither a version property in the project file (or the Directory.Build.props it imports) nor an assembly-level AssemblyVersion attribute in its sources. Every build of such a project produces an assembly stamped 0.0.0.0.

Rationale

The assembly version is part of an assembly’s identity. The runtime uses it to bind references, the GAC and side-by-side deployment use it to keep releases apart, strong naming includes it in the signed identity, and binding redirects are written in terms of it. Package managers and incident triage rely on it to answer "which build is running in production?".

When no version is declared the compiler emits 0.0.0.0 for every build. Two different releases then have the same identity: a redirect cannot distinguish them, a partially updated deployment loads whichever copy the probing rules find first, and a crash dump no longer identifies the build it came from. The failure is silent — nothing warns at build time, and the consequence only appears once a second version of the assembly exists somewhere.

Modern SDK-style projects declare the version in the project file and the SDK generates the attribute during the build, so a project that carries no AssemblyVersion attribute in its sources is not necessarily missing a version. Legacy projects declare the attribute by hand, conventionally in Properties/AssemblyInfo.cs. Either place satisfies the rule; only a project with neither is reported.

AssemblyFileVersion and AssemblyInformationalVersion do not satisfy it — they are informational metadata shown in file properties and carry no part of the assembly identity.

// Properties/AssemblyInfo.cs of a project whose .csproj declares no version property

using System.Reflection;

[assembly: AssemblyTitle("Payments")]
[assembly: AssemblyFileVersion("1.4.0.0")]      // FLAW — file version is not the assembly identity

// The same file, fixed: any of the spellings below satisfies the identity requirement.

[assembly: AssemblyVersion("1.4.0.0")]                          // OK
[assembly: AssemblyVersionAttribute("1.4.0.0")]                 // OK, explicit suffix
[assembly: System.Reflection.AssemblyVersion("1.4.0.0")]        // OK, qualified

The project file is the other half of the verdict:

<!-- OK — the SDK generates [assembly: AssemblyVersion] from any of these -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Version>1.4.0</Version>
  </PropertyGroup>
</Project>

The finding is reported once per project, on the project file itself, because an absent declaration has no place in the source to point at.

Remediation

Declare the version in the project file — <Version> is the usual choice, and it also seeds the package and file versions. <VersionPrefix> (combined with a <VersionSuffix> supplied by the build) and an explicit <AssemblyVersion> are equally accepted.

For a solution that versions all of its projects together, declare the property once in a Directory.Build.props at the repository root; every project below it inherits the value, and the rule consults that file too.

In a legacy project that has no version property, add [assembly: AssemblyVersion("1.0.0.0")] to Properties/AssemblyInfo.cs.

Feed the value from the build pipeline rather than hand-editing it per release, so the version tracks the commit or tag being built.