Summary
Microsoft.EntityFrameworkCore.Tasks' NativeAOT/precompiled-query generation
(_EFGenerateFilesBeforePublish / _EFGenerateFiles / OptimizeDbContext in
Microsoft.EntityFrameworkCore.Tasks.targets) fails for a project that
declares more than one TFM in <TargetFrameworks>, even when publishing for
a single, explicitly selected framework (dotnet publish --framework net11.0).
Normal restore and build/publish (without PublishAot/the Tasks package's
generation step) work correctly for the same project. The failure is
specific to the EF Tasks generation path.
This is distinct from #38951. That issue is about MSBuildWorkspace
losing a custom $(Configuration) value when dotnet ef dbcontext optimize
reopens the project. This issue occurs earlier and through a different
mechanism: a plain MSBuild <MSBuild Targets="Build" Properties="...">
re-invocation inside the Tasks targets executes with $(TargetFramework)
already empty, before MSBuildWorkspace is ever involved.
Repro
Repro.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net10.0;net11.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
<InterceptorsNamespaces>$(InterceptorsNamespaces);Microsoft.EntityFrameworkCore.GeneratedInterceptors</InterceptorsNamespaces>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net11.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="11.0.0-rc.1.26425.128" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="11.0.0-rc.1.26425.128">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive; compile</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tasks" Version="11.0.0-rc.1.26425.128">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net10.0'">
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.12" />
</ItemGroup>
</Project>
Program.cs
using Microsoft.EntityFrameworkCore;
using var db = new BlogContext();
db.Database.EnsureCreated();
var count = db.Blogs.Count();
Console.WriteLine($"Blogs: {count}");
public class Blog
{
public int Id { get; set; }
public string Url { get; set; } = "";
}
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs => Set<Blog>();
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite("Data Source=repro.db");
}
Commands
dotnet restore -p:TargetFrameworks=net11.0
dotnet publish --configuration Release --framework net11.0 --runtime osx-arm64 --no-restore -o out
EF Tasks version tested: Microsoft.EntityFrameworkCore.Tasks 11.0.0-rc.1.26425.128 (matching EF Core / EF Core Design / EF Core Sqlite at the same version). SDK: 11.0.100-rc.1.26425.128 on macOS (osx-arm64). Not tested against other EF11 preview/RC builds; the relevant targets-file logic looked unchanged across the ones inspected.
Observed failure
A plain dotnet build/dotnet publish of the same project (without
PublishAot, or with the Tasks package removed) restores and builds
successfully for both net10.0 and net11.0 individually. The failure
appears specifically once Microsoft.EntityFrameworkCore.Tasks' NativeAOT
generation path runs:
Optimizing DbContext...
.../microsoft.entityframeworkcore.tasks/11.0.0-rc.1.26425.128/buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets(105,5): error : Compilation failed with errors:
.../Program.cs(1,17): error CS0234: The type or namespace name 'EntityFrameworkCore' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?)
.../Program.cs(14,28): error CS0246: The type or namespace name 'DbContext' could not be found (are you missing a using directive or an assembly reference?)
.../Program.cs(16,12): error CS0246: The type or namespace name 'DbSet<>' could not be found (are you missing a using directive or an assembly reference?)
.../Program.cs(17,43): error CS0246: The type or namespace name 'DbContextOptionsBuilder' could not be found (are you missing a using directive or an assembly reference?)
i.e. inside the Tasks-driven re-compilation, the project appears to have
no package references at all — not "wrong TFM's references", but none.
Root cause (confirmed via -v:diag MSBuild log; not speculative beyond this)
Microsoft.EntityFrameworkCore.Tasks.targets (buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets):
<Target Name="_EFGenerateFilesBeforePublish"
AfterTargets="GetCopyToPublishDirectoryItems"
BeforeTargets="GeneratePublishDependencyFile"
Condition="'$(_EFGenerationStage)'=='' And '$(DesignTimeBuild)' != 'True' And ('$(EFScaffoldModelStage)'=='publish' Or '$(EFPrecompileQueriesStage)'=='publish' Or '$(_EFPublishAot)'=='true' Or '$(PublishAot)'=='true')">
<MSBuild Projects="$(MSBuildProjectFullPath)"
Targets="_EFGenerateFiles"
BuildInParallel="$(BuildInParallel)"
ContinueOnError="$(ContinueOnError)"
Properties="Configuration=$(Configuration);Platform=$(Platform);_EFGenerationStage=publish" />
</Target>
<Target Name="_EFGenerateFiles">
<PropertyGroup>
<_EFInnerBuildProperties>Configuration=$(Configuration);Platform=$(Platform);PublishAot=false;_EFGenerationStage=$(_EFGenerationStage)</_EFInnerBuildProperties>
<_EFInnerBuildProperties Condition="'$(PublishAot)'=='true' Or '$(_EFPublishAot)'=='true'">$(_EFInnerBuildProperties);RuntimeIdentifier=;SelfContained=false</_EFInnerBuildProperties>
</PropertyGroup>
<MSBuild Projects="$(MSBuildProjectFullPath)" Targets="Build" BuildInParallel="$(BuildInParallel)" ContinueOnError="$(ContinueOnError)"
Condition="'$(PublishAot)'=='true' Or '$(_EFPublishAot)'=='true'"
Properties="$(_EFInnerBuildProperties)" />
<MSBuild Projects="$(MSBuildProjectFullPath)" Targets="OptimizeDbContext" BuildInParallel="$(BuildInParallel)" ContinueOnError="$(ContinueOnError)"
Properties="$(_EFInnerBuildProperties)" />
<CallTarget Targets="Build" />
</Target>
A -v:diag build log shows the <MSBuild Targets="Build" Properties="$(_EFInnerBuildProperties)"> task invocation with exactly these Global Properties (no TargetFramework):
Task "MSBuild" (TaskId:103)
Task Parameter:
Properties=
Configuration=Release
Platform=AnyCPU
PublishAot=false
_EFGenerationStage=publish
RuntimeIdentifier=
SelfContained=false (TaskId:103)
Task Parameter:Targets=Build (TaskId:103)
Global Properties: (TaskId:103)
Configuration=Release (TaskId:103)
Platform=AnyCPU (TaskId:103)
PublishAot=false (TaskId:103)
_EFGenerationStage=publish (TaskId:103)
RuntimeIdentifier= (TaskId:103)
SelfContained=false (TaskId:103)
Searching the entire re-invoked sub-build's log region (the project instance
that executes Targets="Build" for this call) for Set Property: TargetFramework= finds no occurrence at all. Instead, the SDK's
cross-targeting logic computes:
Added Item(s):
_TargetFramework=
net10.0
net11.0
i.e. the re-invoked build evaluates the project in the outer,
no-single-TFM-selected cross-targeting orchestrator shape rather than a
scoped per-TFM inner build. Because $(TargetFramework) is empty throughout
that project instance's evaluation, the Condition="'$(TargetFramework)' == 'net11.0'" PackageReference ItemGroups never activate (item-group
conditions are evaluated once, at project load, using whatever global
properties the project instance was given) — so the sub-build compiles with
no EF Core/other package references at all, producing the CS0234/CS0246
errors above.
(The [...::TargetFramework=net11.0] suffix MSBuild appends to the error
text comes from the entry-point/outer logging context, not the actual
$(TargetFramework) state inside the failing sub-build — it does not
indicate the sub-build was actually scoped to net11.0.)
Diagnostic experiment: does simply adding TargetFramework=$(TargetFramework) fix it?
No. I patched a local copy of the installed Microsoft.EntityFrameworkCore.Tasks.targets to change:
<_EFInnerBuildProperties>Configuration=$(Configuration);Platform=$(Platform);PublishAot=false;_EFGenerationStage=$(_EFGenerationStage)</_EFInnerBuildProperties>
to:
<_EFInnerBuildProperties>Configuration=$(Configuration);Platform=$(Platform);PublishAot=false;_EFGenerationStage=$(_EFGenerationStage);TargetFramework=$(TargetFramework)</_EFInnerBuildProperties>
and re-ran the identical repro. The failure was unchanged — same
CS0234/CS0246 errors. A second -v:diag log showed why: at the point
_EFInnerBuildProperties is evaluated (inside _EFGenerateFilesBeforePublish,
which hooks in via AfterTargets="GetCopyToPublishDirectoryItems"
/BeforeTargets="GeneratePublishDependencyFile"), $(TargetFramework) is
already empty in the entry-point project instance itself — my added
TargetFramework=$(TargetFramework) simply evaluated to
TargetFramework= (empty) and changed nothing. So the defect isn't only
that the nested <MSBuild Properties="..."> call drops an otherwise-correct
$(TargetFramework) value — $(TargetFramework) isn't bound to a single
value in the project instance these hook points execute in, for a
multi-targeted project. I do not have a confirmed fix; I'm reporting the
observed behavior and the boundary of what I verified, not a proposed patch.
Related but distinct
#38951 — dotnet ef dbcontext optimize --precompile-queries doesn't pass
$(Configuration) to MSBuildWorkspace, breaking non-default build
configurations. That's a different mechanism (a C#-API MSBuildWorkspace
project reopen inside the OptimizeDbContext task itself) that only matters
after the project has a resolved $(TargetFramework)/$(Configuration) —
this issue happens earlier, in the plain-MSBuild-task re-invocation, and
affects a genuinely multi-targeted project shape regardless of whether
$(Configuration) is a standard or custom value.
Summary
Microsoft.EntityFrameworkCore.Tasks' NativeAOT/precompiled-query generation(
_EFGenerateFilesBeforePublish/_EFGenerateFiles/OptimizeDbContextinMicrosoft.EntityFrameworkCore.Tasks.targets) fails for a project thatdeclares more than one TFM in
<TargetFrameworks>, even when publishing fora single, explicitly selected framework (
dotnet publish --framework net11.0).Normal restore and build/publish (without
PublishAot/the Tasks package'sgeneration step) work correctly for the same project. The failure is
specific to the EF Tasks generation path.
This is distinct from #38951. That issue is about
MSBuildWorkspacelosing a custom
$(Configuration)value whendotnet ef dbcontext optimizereopens the project. This issue occurs earlier and through a different
mechanism: a plain MSBuild
<MSBuild Targets="Build" Properties="...">re-invocation inside the Tasks targets executes with
$(TargetFramework)already empty, before
MSBuildWorkspaceis ever involved.Repro
Repro.csproj
Program.cs
Commands
EF Tasks version tested:
Microsoft.EntityFrameworkCore.Tasks11.0.0-rc.1.26425.128(matching EF Core / EF Core Design / EF Core Sqlite at the same version). SDK: 11.0.100-rc.1.26425.128 on macOS (osx-arm64). Not tested against other EF11 preview/RC builds; the relevant targets-file logic looked unchanged across the ones inspected.Observed failure
A plain
dotnet build/dotnet publishof the same project (withoutPublishAot, or with theTaskspackage removed) restores and buildssuccessfully for both
net10.0andnet11.0individually. The failureappears specifically once
Microsoft.EntityFrameworkCore.Tasks' NativeAOTgeneration path runs:
i.e. inside the Tasks-driven re-compilation, the project appears to have
no package references at all — not "wrong TFM's references", but none.
Root cause (confirmed via
-v:diagMSBuild log; not speculative beyond this)Microsoft.EntityFrameworkCore.Tasks.targets(buildTransitive/Microsoft.EntityFrameworkCore.Tasks.targets):A
-v:diagbuild log shows the<MSBuild Targets="Build" Properties="$(_EFInnerBuildProperties)">task invocation with exactly these Global Properties (noTargetFramework):Searching the entire re-invoked sub-build's log region (the project instance
that executes
Targets="Build"for this call) forSet Property: TargetFramework=finds no occurrence at all. Instead, the SDK'scross-targeting logic computes:
i.e. the re-invoked build evaluates the project in the outer,
no-single-TFM-selected cross-targeting orchestrator shape rather than a
scoped per-TFM inner build. Because
$(TargetFramework)is empty throughoutthat project instance's evaluation, the
Condition="'$(TargetFramework)' == 'net11.0'"PackageReferenceItemGroups never activate (item-groupconditions are evaluated once, at project load, using whatever global
properties the project instance was given) — so the sub-build compiles with
no EF Core/other package references at all, producing the
CS0234/CS0246errors above.
(The
[...::TargetFramework=net11.0]suffix MSBuild appends to the errortext comes from the entry-point/outer logging context, not the actual
$(TargetFramework)state inside the failing sub-build — it does notindicate the sub-build was actually scoped to net11.0.)
Diagnostic experiment: does simply adding
TargetFramework=$(TargetFramework)fix it?No. I patched a local copy of the installed
Microsoft.EntityFrameworkCore.Tasks.targetsto change:to:
and re-ran the identical repro. The failure was unchanged — same
CS0234/CS0246errors. A second-v:diaglog showed why: at the point_EFInnerBuildPropertiesis evaluated (inside_EFGenerateFilesBeforePublish,which hooks in via
AfterTargets="GetCopyToPublishDirectoryItems"/
BeforeTargets="GeneratePublishDependencyFile"),$(TargetFramework)isalready empty in the entry-point project instance itself — my added
TargetFramework=$(TargetFramework)simply evaluated toTargetFramework=(empty) and changed nothing. So the defect isn't onlythat the nested
<MSBuild Properties="...">call drops an otherwise-correct$(TargetFramework)value —$(TargetFramework)isn't bound to a singlevalue in the project instance these hook points execute in, for a
multi-targeted project. I do not have a confirmed fix; I'm reporting the
observed behavior and the boundary of what I verified, not a proposed patch.
Related but distinct
#38951 —
dotnet ef dbcontext optimize --precompile-queriesdoesn't pass$(Configuration)toMSBuildWorkspace, breaking non-default buildconfigurations. That's a different mechanism (a C#-API
MSBuildWorkspaceproject reopen inside the
OptimizeDbContexttask itself) that only mattersafter the project has a resolved
$(TargetFramework)/$(Configuration)—this issue happens earlier, in the plain-MSBuild-task re-invocation, and
affects a genuinely multi-targeted project shape regardless of whether
$(Configuration)is a standard or custom value.