Skip to content

fix: resolve $(RootNamespace) in AssemblyName - #1128

Merged
mtsfoni merged 1 commit into
CycloneDX:masterfrom
Eljees:fix/917-resolve-rootnamespace-in-assemblyname
Oct 12, 2026
Merged

mtsfoni merged 1 commit into
CycloneDX:masterfrom
Eljees:fix/917-resolve-rootnamespace-in-assemblyname

Conversation

@Eljees

@Eljees Eljees commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

Fixes #917

The defect

GetAssemblyNameAndVersion resolves $(MSBuildProjectName) but returns $(RootNamespace) as a raw literal. <AssemblyName>$(RootNamespace)</AssemblyName> is a common idiom that gets copy-pasted across projects, and the unresolved token is byte-for-byte the same in all of them.

RecursivelyGetProjectReferencesAsync keys its dictionary on the project name, so as soon as a root project references two projects that both use the idiom, the run dies with:

System.ArgumentException: An item with the same key has already been added. Key: $(RootNamespace)

even though the two projects resolve to different assembly names under MSBuild.

The change

Resolve the token from the project's own <RootNamespace> element, checking the same three namespace shapes the surrounding code already handles (no namespace, msbuild: on the element, msbuild: on the whole path).

When <RootNamespace> is missing or itself unusable, fall back to the project file name — the same fallback the $(MSBuildProjectName) branch uses. The unusable case matters here: the workaround suggested in the issue thread is <RootNamespace>$(AssemblyName)</RootNamespace>, which would resolve back into the token we started from, so it is excluded explicitly rather than left to loop.

What I ran

.NET SDK 10, dotnet test CycloneDX.Tests/CycloneDX.Tests.csproj, net10.0 target:

  • control, ProjectFileService.cs as it is on master: Failed 3, Passed 26, Total 29 for ProjectFileServiceTests, and the reproducer fails with exactly the An item with the same key has already been added. Key: $(RootNamespace) above
  • with the change: Failed 0, Passed 29, Total 29
  • whole test project: Passed 221, Skipped 2, Failed 0

The net8.0 target of the test project could not run in that container (no .NET 8 runtime present), so those numbers are the net10.0 target only; CI covers both.

Three tests are added: the two-referenced-projects reproducer that crashed before, a direct check that the token resolves to the project's own root namespace, and one pinning the file-name fallback so the $(AssemblyName) workaround cannot resolve into a loop.

@Eljees
Eljees requested a review from a team as a code owner September 20, 2026 10:36
GetAssemblyNameAndVersion already resolves $(MSBuildProjectName) but returned
the raw literal for $(RootNamespace). That token is identical in every project
that uses the idiom, so a root project referencing two of them collides on the
same dictionary key in RecursivelyGetProjectReferencesAsync and the run fails
with "An item with the same key has already been added. Key: $(RootNamespace)",
even though the projects resolve to different names under MSBuild.

Resolve the token from the project`s own RootNamespace element, in all three
namespace shapes the file already handles. When RootNamespace is itself
unusable - notably the documented workaround that points it back at
$(AssemblyName) - fall back to the project file name, the same fallback the
$(MSBuildProjectName) path uses, so the two cannot resolve into each other.

Fixes CycloneDX#917

Signed-off-by: Eljees <3.14hell@gmail.com>
@mtsfoni
mtsfoni force-pushed the fix/917-resolve-rootnamespace-in-assemblyname branch from f84b495 to b35446b Compare October 12, 2026 00:00
@mtsfoni
mtsfoni merged commit a8f98a9 into CycloneDX:master Oct 12, 2026
14 checks passed
This was referenced Oct 12, 2026
This was referenced Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Can't handle referenced build properties for AssemblyName

2 participants