microsoft / microsoft/aspire

Support custom MSBuild settings in Aspire EF Core migration operations

Open
#20,162 1 comment 0 reactions 0 assignees View on GitHub
area-integrations entityframework triage:bot-seen
Dominant language
C#
Stars
6.3k
Forks
991
Avg merge
2d 15h
Merged PRs (30d)
196

Description

### Is there an existing issue for this?

- [x] I have searched the existing issues.

### Is your feature request related to a problem? Please describe the problem.

This tracks a remaining limitation of #19997, which enables EF Core migrations for projects modeled with `AddDotnetProject()`. We would like to work with the EF team on a supported way for migration operations to use the same build settings as the application.

Aspire allows an AppHost to supply build-only inputs through `WithBuildEnvironment(...)`. These inputs are applied as **MSBuild global properties** during the coordinated project build, preserving their precedence over ordinary project-file assignments. The shared `WithDotnetProgramBuildEnvironment(...)` API and custom `IProjectMetadata.BuildEnvironment` can introduce the same requirement.

The `dotnet-ef` CLI supports selected settings such as configuration, target framework, and runtime identifier, but does not expose a general mechanism for passing arbitrary MSBuild global properties through its project evaluation and build steps.

**Building the application first and using `--no-build` is not sufficient.** EF still evaluates the target and startup projects to discover output paths, assemblies, dependencies, and other metadata. Without the same global properties, that evaluation can disagree with Aspire's successful build. EF can then fail because an assembly is missing, or use stale or differently configured assemblies if output exists at the location it selects.

#### Illustrative scenario

In an existing EF-enabled `Api.csproj`, make the output directory depend on a build property:

```xml

default
bin\$(BUILD_FLAVOR)\$(Configuration)\

```

Configure the project in the AppHost:

```csharp
var api = builder.AddDotnetProject("api", @"..\Api\Api.csproj")
.WithBuildEnvironment("BUILD_FLAVOR", "custom");

api.AddEFMigrations("api-migrations");
```

Aspire's global property overrides the project-file assignment, so it builds under `bin\custom\...`. When an EF dashboard command subsequently runs, EF's separate evaluation can instead select `bin\default\...`.

The underlying tooling mismatch can also be illustrated independently of Aspire:

```powershell
dotnet build .\Api\Api.csproj -p:BUILD_FLAVOR=custom
dotnet ef migrations script --project .\Api\Api.csproj --no-build
```

The second command has no equivalent supported option to supply that custom global property. This is a source-derived scenario, not an executed minimal reproduction attached to this issue.

The issue is not limited to output directories: build properties can also affect conditional compilation and references, so matching the assembly path alone is not necessarily enough.

#### Current handling in #19997

The PR deliberately warns once per requested EF operation when participating projects have Aspire-specific build customizations, then continues on a best-effort basis. Build readiness is handled separately; waiting for compilation does not solve the evaluation mismatch.

Run-mode operations retain `--no-build`. Publish-time SQL script and migration bundle generation allow EF to build, but those builds still lack a supported way to receive the same custom properties. Consequently, both local migration commands and published migration artifacts are in scope.

### Describe the solution you'd like

Agree with the EF team on a supported contract for carrying the relevant build context into EF operations, then integrate it into Aspire. This issue intentionally does not prescribe a particular CLI syntax or implementation.

Possible approaches to discuss:

- Allow custom MSBuild properties, potentially through a response file or structured input, and honor them consistently during metadata evaluation and applicable restore/build steps, including the nested publish used to produce migration bundles.
- Provide a supported way to consume explicitly selected, already-built artifacts and their evaluation metadata for `--no-build` operations, with a corresponding solution for operations that must build or publish.

The solution should:

- Preserve global-property precedence, and define scoping/conflict behavior for separate startup and migrations projects and for EF-owned build settings.
- Make `--no-build` resolve the outputs produced with the requested settings, rather than silently selecting another build.
- Keep build-only inputs separate from application runtime configuration, and avoid unnecessarily disclosing property values in diagnostics.
- Preserve coordinated-build readiness, cancellation, and failure propagation without waiting for the application to start; `api.WaitFor(migrations)` must remain supported.

Completion should include focused coverage for custom output paths and unconditional project-property assignments across local commands, SQL script generation, and bundle generation, including a separate migrations project.

**Alternatives and current workaround:** Where equivalent, place the required settings in shared `.csproj` or `Directory.Build.props` configuration so Aspire and EF evaluate the same values. This is not a general replacement for dynamic, resource-specific AppHost configuration.

Copying values to runtime `WithEnvironment(...)` is not equivalent: project-file assignments can override environment-derived MSBuild properties, and build-only settings would also become runtime inputs. Arguments after EF's `--` separator are application arguments, not MSBuild arguments. Relying on EF's private launcher/assembly layout would introduce version coupling rather than a supported integration.

### Additional context

- Follow-up to #19997, particularly the [decision to warn and continue rather than claim full property propagation](https://github.com/microsoft/aspire/pull/19997#discussion_r3980841115).
- Broader Aspire migration tracking: #7106.
- [Aspire's documented compatibility limitation at the PR head](https://github.com/microsoft/aspire/blob/6edb33667ff84b7c919c67ed8929041f37ce7175/src/Aspire.Hosting.EntityFrameworkCore/README.md#coordinated-builds-and-custom-build-inputs).
- EF tooling sources examined: `dotnet-ef` **10.0.12**, the latest stable release when this draft was prepared. [ProjectOptions](https://github.com/dotnet/efcore/blob/v10.0.12/src/dotnet-ef/ProjectOptions.cs) defines the supported options; [RootCommand](https://github.com/dotnet/efcore/blob/v10.0.12/src/dotnet-ef/RootCommand.cs) evaluates both projects before its `--no-build` check; [Project](https://github.com/dotnet/efcore/blob/v10.0.12/src/dotnet-ef/Project.cs) constructs metadata/build invocations; [MigrationsBundleCommand](https://github.com/dotnet/efcore/blob/v10.0.12/src/ef/Commands/MigrationsBundleCommand.cs) performs the additional bundle publish.
- [MSBuild environment-variable precedence](https://learn.microsoft.com/visualstudio/msbuild/how-to-use-environment-variables-in-a-build).

Contributor guide

Open the contributing guide

Research direction

Start with Aspire's documented coordinated-build limitation and the cited EF tooling sources: ProjectOptions.cs, RootCommand.cs, Project.cs, and MigrationsBundleCommand.cs. Trace how both projects are evaluated and how local, SQL script, and bundle operations build or publish. Done means an agreed supported build-context contract is integrated with focused coverage for custom output paths and project properties, including a separate migrations project.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
build-system, databases, devtools
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.