Skip to content

Commit

Permalink
Document the SDK breaking change affecting EF tools
Browse files Browse the repository at this point in the history
  • Loading branch information
AndriySvyryd committed Jan 17, 2025
1 parent c3e2876 commit b9d5ead
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 6 deletions.
7 changes: 1 addition & 6 deletions entity-framework/core/miscellaneous/internals/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
43 changes: 43 additions & 0 deletions entity-framework/core/what-is-new/ef-core-9.0/breaking-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down Expand Up @@ -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

<a name="tools-design"></a>

### `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
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="*.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
```

#### 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
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<Publish>true</Publish>
</PackageReference>
```

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

<a name="unhex"></a>
Expand Down

0 comments on commit b9d5ead

Please sign in to comment.