Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use AssemblyLoadContext to load EFC.Design #35527

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Conversation

AndriySvyryd
Copy link
Member

Fixes #35265
Part of #18840

@AndriySvyryd AndriySvyryd requested a review from a team as a code owner January 25, 2025 02:18
@AndriySvyryd
Copy link
Member Author

@baronfel @ViktorHofer @rainersigwald Please take a look at the first commit to verify whether this is a sane approach to find and load a referenced PrivateAssets assembly when the .deps.json file is not available.

Choose a reason for hiding this comment

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

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

Files not reviewed (10)
  • src/EFCore.Tasks/buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets: Language not supported
  • src/EFCore.Tools/tools/EntityFrameworkCore.psm1: Language not supported
  • src/ef/Properties/Resources.Designer.cs: Language not supported
  • src/ef/Properties/Resources.resx: Language not supported
  • src/EFCore.Tasks/Tasks/Internal/OperationTaskBase.cs: Evaluated as low risk
  • src/dotnet-ef/Project.cs: Evaluated as low risk
  • src/dotnet-ef/RootCommand.cs: Evaluated as low risk
  • src/ef/AppDomainOperationExecutor.cs: Evaluated as low risk
  • src/ef/Commands/DbContextOptimizeCommand.cs: Evaluated as low risk
  • src/ef/Commands/MigrationsHasPendingModelChangesCommand.cs: Evaluated as low risk
Comments suppressed due to low confidence (1)

src/ef/Commands/MigrationsBundleCommand.cs:39

  • The variable 'context' should be nullable or have a null check to ensure consistency with the nullable 'version' variable.
string context;
@SamMonoRT
Copy link
Member

@agocke - please add relevant folks to review if this is a sane approach to find and load a referenced PrivateAssets assembly when the .deps.json file is not available.

Copy link
Member

@rainersigwald rainersigwald left a comment

Choose a reason for hiding this comment

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

Sorry, I missed this earlier. MSBuild loads plugins (tasks, loggers) in an ALC that ensures unification for MSBuild assemblies and supports references from the plugin DLL to other DLLs placed next to it, both with and without a .deps.json: https://github.com/dotnet/msbuild/blob/353c0f3d37957cc98bfa6a76b568d70d12193fc3/src/Shared/MSBuildLoadContext.cs

Is that sort of transitive reference something that is relevant to y'all?

Copy link
Member

@agocke agocke left a comment

Choose a reason for hiding this comment

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

I need more info on what this code is trying to do and what isolation guarantees it’s supposed to have.

I also haven’t reviewed any of the desktop fx load logic

@@ -17,10 +20,15 @@ internal class ReflectionOperationExecutor : OperationExecutorBase
private const string ReportHandlerTypeName = "Microsoft.EntityFrameworkCore.Design.OperationReportHandler";
private const string ResultHandlerTypeName = "Microsoft.EntityFrameworkCore.Design.OperationResultHandler";
private readonly Type _resultHandlerType;
private string? _efcoreVersion;
#if !NET472
Copy link
Member

Choose a reason for hiding this comment

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

Use a less specific tfm, like NET. Otherwise this will break when we update the tfm. Same for the rest of the #if in this PR.

@@ -47,7 +55,20 @@ public ReflectionOperationExecutor(

AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;

_commandsAssembly = Assembly.Load(new AssemblyName { Name = DesignAssemblyName });
#if !NET472
_commandsAssembly = AssemblyLoadContext.LoadFromAssemblyName(new AssemblyName(DesignAssemblyName));
Copy link
Member

Choose a reason for hiding this comment

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

You can just load with the string name.

_assemblyLoadContext = AssemblyLoadContext.Default;
}

return AssemblyLoadContext.Default;
Copy link
Member

Choose a reason for hiding this comment

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

I don’t understand this logic. Why is using an ALC opportunistic? It seems like you either need one or you don’t.

Copy link
Member Author

Choose a reason for hiding this comment

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

ALC is always used, this code just ensures that the Resolving handler is registered even if DesignAssemblyPath is set after the first time AssemblyLoadContext is requested.

@AndriySvyryd
Copy link
Member Author

AndriySvyryd commented Mar 6, 2025

I need more info on what this code is trying to do and what isolation guarantees it’s supposed to have.

This code runs when EF tools are executed and loads EFC.Design reference from the user's project (usually with PrivateAssets="all") and later usually loads the assembly built from the project. No isolation is necessary since the process terminates after performing the requested operation. ALC is leveraged to load the assemblies in a more robust manner.

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.

React to deps.json change wrt PrivateAssets
4 participants