Skip to content

fix(tasks): stop loading plugin assemblies with Assembly.LoadFrom - #112

Merged
TomProkop merged 1 commit into
masterfrom
fix/applyversionnumber-assembly-collision
Aug 11, 2026
Merged

fix(tasks): stop loading plugin assemblies with Assembly.LoadFrom#112
TomProkop merged 1 commit into
masterfrom
fix/applyversionnumber-assembly-collision

Conversation

@TomProkop

Copy link
Copy Markdown
Member

Summary

  • ApplyVersionNumber and its sibling ApplyPluginVersionNumberInSolution intermittently fail with MSB4018 / System.IO.FileLoadException: ... Assembly with same name is already loaded, surfacing as a flaky failure building a Dataverse solution project that references a plugin assembly.
  • Root cause: both tasks run in-process inside the MSBuild worker node. MSBuild defaults to /nodeReuse:true, so a worker node persists across separate dotnet build/dotnet publish CLI invocations (~15 min idle timeout). Assembly.LoadFrom routes through AssemblyLoadContext.Default, so if a same-identity plugin assembly gets loaded a second time in a reused node, the CLR throws FileLoadException. Confirmed byte-identical in 1.8.2 and 1.8.3 — not something the 1.8.3 bump addressed. The sibling task has the identical pattern.
  • Fix: neither task ever needs to execute the assembly — only its name/version/public key token. Replaced Assembly.LoadFrom(path) with AssemblyName.GetAssemblyName(path), which reads that identity straight from the PE headers without loading anything into any AssemblyLoadContext, eliminating the collision mechanism entirely (rather than working around a specific trigger condition).

Testing

  • dotnet build on TALXIS.DevKit.Build.Dataverse.Tasks.csproj: 0 errors.
  • Direct repro of the failure mechanism: calling Assembly.LoadFrom twice in one process on the same assembly identity can throw FileLoadException/FileNotFoundException depending on file state; calling AssemblyName.GetAssemblyName twice on the same path never touches any AssemblyLoadContext and cannot hit this failure mode by construction.
  • End-to-end: built the fix, patched it into a local NuGet cache copy of talxis.devkit.build.dataverse.tasks 1.8.3, and ran TALXIS/alm-lab's full LOCAL-DRY-RUN.md flow (CP01→CP08, the exact sequence that originally reproduced the crash), plus 5 additional immediate dotnet build rebuilds of the whole solution in the same shell session to maximize MSBuild node-reuse pressure. All builds succeeded with 0 errors.

Generated by Claude Code

ApplyVersionNumber and ApplyPluginVersionNumberInSolution both run
in-process inside the MSBuild worker node, which defaults to node
reuse (/nodeReuse:true) and persists across separate dotnet build/
dotnet publish CLI invocations. Assembly.LoadFrom routes through
AssemblyLoadContext.Default, so loading a same-identity plugin
assembly a second time in a reused node throws
"FileLoadException: Assembly with same name is already loaded" -
intermittently, since it depends on which builds happen to share a
live node. This showed up in the wild as a flaky MSB4018 failure
building a Dataverse solution project that both directly and
transitively (via another project's ProjectReference) contains a
plugin assembly reference.

Both tasks only ever need the assembly's name/version/public key
token, never to execute it, so switch to
AssemblyName.GetAssemblyName(path), which reads that identity
straight from the PE headers without loading anything into any
AssemblyLoadContext - eliminating the collision by construction.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Replaces plugin assembly loading with metadata-only identity reads, preventing assembly collisions in reused MSBuild workers.

Changes:

  • Uses AssemblyName.GetAssemblyName in both versioning tasks.
  • Updates assembly identity/version access accordingly.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/Dataverse/Tasks/Tasks/ApplyVersionNumber.cs Reads plugin identities without loading assemblies.
src/Dataverse/Tasks/Tasks/ApplyPluginVersionNumberInSolution.cs Reads plugin versions directly from PE metadata.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@TomProkop
TomProkop merged commit d718248 into master Aug 11, 2026
1 check passed
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.

3 participants