From b9d5ead5fac8354550c2d4a3ddf32c97d641064e Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Fri, 17 Jan 2025 15:48:19 -0800 Subject: [PATCH] Document the SDK breaking change affecting EF tools --- .../core/miscellaneous/internals/tools.md | 7 +-- .../ef-core-9.0/breaking-changes.md | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/entity-framework/core/miscellaneous/internals/tools.md b/entity-framework/core/miscellaneous/internals/tools.md index 0475c90921..002c94b71b 100644 --- a/entity-framework/core/miscellaneous/internals/tools.md +++ b/entity-framework/core/miscellaneous/internals/tools.md @@ -23,12 +23,7 @@ There are two primary inputs to this command: the startup project and the target It reads information about the projects by injecting an MSBuild .targets file and calling the custom MSBuild target. The .targets file is compiled into dotnet-ef as an embedded resource. The source is located at [src/dotnet-ef/Resources/EntityFrameworkCore.targets](https://github.com/dotnet/efcore/blob/main/src/dotnet-ef/Resources/EntityFrameworkCore.targets). -It has a bit of logic at the beginning to handle multi-targeting projects. Essentially, it just picks the first target framework and re-invokes itself. After a single target framework has been determined, it writes several MSBuild properties like AssemblyName, OutputPath, RootNamespace, etc. to a temporary file that dotnet-ef then reads. - -> [!TIP] -> .NET 8 adds a new, streamlined way to read MSBuild properties that will enable us to remove this .targets file. See issue [#32113](https://github.com/dotnet/efcore/issues/32113). - -We need to inject this target into both the startup and target project. We do that by leveraging an MSBuild hook created for NuGet and other package managers. That hook automatically loads any file under `$(MSBuildProjectExtensionsPath)` with a name matching the pattern `$(MSBuildProjectName).*.targets`. Unfortunately, we don't know the actual value of the MSBuildProjectExtensionsPath property, and we need it before we can read any MSBuild properties. So, we assume it's set to the default value of `$(MSBuildProjectDirectory)\obj`. If it's not, the user must specify it using the `--msbuildprojectextensionspath` option. +It has a bit of logic at the beginning to handle multi-targeting projects. Essentially, it just picks the first target framework and re-invokes itself. After a single target framework has been determined, it gets several MSBuild properties like AssemblyName, OutputPath, RootNamespace, etc. After we've collected the project information, we compile the startup project. We assume that the target project will also be compiled transitively. diff --git a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md index 4946eb93d2..b0449eec6e 100644 --- a/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md +++ b/entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md @@ -27,6 +27,7 @@ EF Core 9 targets .NET 8. This means that existing applications that target .NET |:----------------------------------------------------------------------------------------------------------|------------| | [Exception is thrown when applying migrations if there are pending model changes](#pending-model-changes) | High | | [Exception is thrown when applying migrations in an explicit transaction](#migrations-transaction) | High | +| [`Microsoft.EntityFrameworkCore.Design` not found when using EF tools](#tools-design) | Medium | | [`EF.Functions.Unhex()` now returns `byte[]?`](#unhex) | Low | | [SqlFunctionExpression's nullability arguments' arity validated](#sqlfunctionexpression-nullability) | Low | | [`ToString()` method now returns empty string for `null` instances](#nullable-tostring) | Low | @@ -114,6 +115,48 @@ Otherwise, if your scenario requires an explicit transaction and you have other options.ConfigureWarnings(w => w.Ignore(RelationalEventId.MigrationsUserTransactionWarning)) ``` +## Medium-impact changes + + + +### `Microsoft.EntityFrameworkCore.Design` not found when using EF tools + +[Tracking Issue #35265](https://github.com/dotnet/efcore/issues/35265) + +#### Old behavior + +Previusly, the EF tools required `Microsoft.EntityFrameworkCore.Design` to be referenced in the following way. + +```XML + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + +``` + +#### New behavior + +Starting with .NET SDK 9.0.200 an exception is thrown when an EF tool is invoked: +> :::no-loc text="Could not load file or assembly 'Microsoft.EntityFrameworkCore.Design, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified."::: + +#### Why + +EF tools were relying on an undocumented behavior of .NET SDK that caused private assets to be included in the generated `.deps.json` file. This was fixed in [sdk#45259](https://github.com/dotnet/sdk/pull/45259). Unfortunately, the EF change to account for this doesn't meet the servicing bar for EF 9.0.x, so it will be fixed in EF 10. + +#### Mitigations + +As a workaround before EF 10 is released you can mark the `Design` assembly reference as publishable: + +```XML + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + true + +``` + +This will include it in the generated `.deps.json` file, but has a side effect of copying `Microsoft.EntityFrameworkCore.Design.dll` to the output and publish folders. + ## Low-impact changes