Repository navigation
Conversation
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
force-pushed
the
fix/917-resolve-rootnamespace-in-assemblyname
branch
from
October 12, 2026 00:00
f84b495 to
b35446b
Compare
This was referenced Oct 12, 2026
Merged
This was referenced Oct 16, 2026
Merged
Merged
This was referenced Oct 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #917
The defect
GetAssemblyNameAndVersionresolves$(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.RecursivelyGetProjectReferencesAsynckeys 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: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.0target:ProjectFileService.csas it is onmaster: Failed 3, Passed 26, Total 29 forProjectFileServiceTests, and the reproducer fails with exactly theAn item with the same key has already been added. Key: $(RootNamespace)aboveThe
net8.0target of the test project could not run in that container (no .NET 8 runtime present), so those numbers are thenet10.0target 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.