Skip to content

Unload target assemblies before publishing the migrations bundle#38456

Draft
ajcvickers wants to merge 2 commits into
dotnet:mainfrom
ajcvickers:fix/25555-bundle-unload-assembly-context
Draft

Unload target assemblies before publishing the migrations bundle#38456
ajcvickers wants to merge 2 commits into
dotnet:mainfrom
ajcvickers:fix/25555-bundle-unload-assembly-context

Conversation

@ajcvickers

Copy link
Copy Markdown
Contributor

Fixes #25555

dotnet ef migrations bundle loads the target and startup assemblies into the tool process to discover the DbContext, then shells out to dotnet publish, which rebuilds and overwrites those same bin...*.dll files. On Windows a loaded assembly file is locked, so the copy fails with MSB3027/MSB3021 ("being used by another process"). The assemblies were loaded into the non-collectible default AssemblyLoadContext, so they could never be released while the tool process was alive.

Load them into a collectible AssemblyLoadContext instead and unload it when the executor is disposed (before publish runs), releasing the files.

Fixes dotnet#25555

`dotnet ef migrations bundle` loads the target and startup assemblies into
the tool process to discover the DbContext, then shells out to
`dotnet publish`, which rebuilds and overwrites those same bin\...\*.dll
files. On Windows a loaded assembly file is locked, so the copy fails with
MSB3027/MSB3021 ("being used by another process"). The assemblies were
loaded into the non-collectible default AssemblyLoadContext, so they could
never be released while the tool process was alive.

Load them into a collectible AssemblyLoadContext instead and unload it when
the executor is disposed (before publish runs), releasing the files.
@ajcvickers

ajcvickers commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

/cc @bricelam, @AndriySvyryd. For more information, see the analysis on #25555.

@ajcvickers

Copy link
Copy Markdown
Contributor Author

Note I'm going to do Windows validation on this before taking this out of draft. I don't dev on Windows anymore, so it may take a bit of time to setup.

The recursive temp-dir delete in the test's finally ran immediately after the
load context was unloaded. On Windows the OS can release the assembly's file
handle slightly after the context is collected, so the delete intermittently
threw UnauthorizedAccessException and masked the (passing) assertion. Unix
allows deleting a file with an open handle, so this only surfaced on Windows
CI. Retry the cleanup briefly and give up quietly; it is a test-cleanup
concern only (in the real tool, publish runs much later).

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

This PR addresses a Windows-specific failure in dotnet ef migrations bundle where the tool process keeps target/startup assemblies loaded (and therefore file-locked) while subsequently running dotnet publish, which tries to overwrite those same assemblies. The intended fix is to load user assemblies into a collectible AssemblyLoadContext and unload it when the executor is disposed (before publish runs).

Changes:

  • Update ReflectionOperationExecutor to create a collectible AssemblyLoadContext and unload it during Dispose().
  • Add a regression test to verify that the target assembly is no longer loaded after disposing the executor.
  • Update ef.Tests project settings/references to support the new test scenario (preserved compilation context and assembly aliasing).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/ef/ReflectionOperationExecutor.cs Introduces collectible ALC creation and explicit unload logic in Dispose() to release user assemblies.
test/ef.Tests/ReflectionOperationExecutorTest.cs Adds a regression test asserting the target assembly is unloaded after executor disposal.
test/ef.Tests/ef.Tests.csproj Enables PreserveCompilationContext (needed by BuildSource/DependencyContext) and adds an alias for the ef tool project reference for the new test.

Comment on lines 156 to 160
protected override void Execute(string operationName, object resultHandler, IDictionary arguments)
=> Activator.CreateInstance(
_commandsAssembly.GetType(ExecutorTypeName + "+" + operationName, throwOnError: true, ignoreCase: true)!,
_executor,
resultHandler,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bundle-Migration errors with "cannot access file...being used by another process"

3 participants