Skip to content

Comments

[dotnet-watch] File based programs, build improvements and polyglot Aspire pre-requisites#52648

Open
tmat wants to merge 14 commits intodotnet:release/10.0.3xxfrom
tmat:FileBasedPrograms
Open

[dotnet-watch] File based programs, build improvements and polyglot Aspire pre-requisites#52648
tmat wants to merge 14 commits intodotnet:release/10.0.3xxfrom
tmat:FileBasedPrograms

Conversation

@tmat
Copy link
Member

@tmat tmat commented Jan 23, 2026

Multiple changes building on top of each other -- recommended to review commit-by-commit:

  • Switches to HotReloadMSBuildWorkspace introduced by HotReloadMSBuildWorkspace roslyn#81577 -- allows us to remove OOP build host and avoid extra design-time build.
  • Implements support for file based programs:
    • Adds --file command line switch
    • Provides custom ProjectInstance factory to ProjectGraph loader, which synthesizes project for .cs file.
  • Uses msbuild BuildManager type to parallelize DTB
    • Improves loading of a graph of 108 projects from 202s to 17s on 48 core CPU.
  • Allows loading project graphs with multiple roots to support polyglot Aspire, where the app host doesn't have references to resource projects (resource projects are the roots of the graph).
  • Improves auto-restart logic to restart projects that do not support Hot Reload.
    • E.g. AOT trimmed projects, F# projects, projects with TFM < 6.0, projects that fail to establish browser refresh connection, etc.)
  • Make arguments to log messages strongly typed (MessageDescriptor<TArgs>).
    • To avoid mistakes when passing arguments
    • To allow future polyglot Aspire impl to define ILogger that forwards select status messages to Aspire controller
  • Fixes a race condition that occurs when shutdown is requested after the process is launched but before the newly created RunningProject is published.
  • Fix race condition that can occur when shutdown is requested while Aspire session is being started.
    • The Aspire service factory may be disposed while a session is being started, before the session object gets registered. The newly created process gets orphaned and doesn't exit before the dotnet watch process terminates. This causes a test that validates termination of all processes to hang.

Fixes #51469

@tmat tmat changed the base branch from main to release/10.0.3xx January 23, 2026 00:14
@tmat tmat force-pushed the FileBasedPrograms branch from 1e151de to 52da47c Compare January 30, 2026 19:41
@tmat tmat force-pushed the FileBasedPrograms branch from 52da47c to deba64e Compare February 7, 2026 20:07
@tmat tmat changed the title File based programs File based programs++ Feb 7, 2026
@tmat tmat force-pushed the FileBasedPrograms branch 2 times, most recently from 13caf2c to b82a003 Compare February 10, 2026 17:05
@tmat tmat force-pushed the FileBasedPrograms branch 2 times, most recently from bc1492b to 79cbd69 Compare February 16, 2026 19:25
@tmat tmat force-pushed the FileBasedPrograms branch 3 times, most recently from 71b9082 to 9225359 Compare February 19, 2026 01:06
@tmat tmat changed the title File based programs++ [dotnet-watch] File based programs, build improvements and polyglot Aspire pre-requisites Feb 19, 2026
@tmat tmat force-pushed the FileBasedPrograms branch 5 times, most recently from e98f949 to f1c8cf8 Compare February 20, 2026 00:54
@tmat tmat marked this pull request as ready for review February 20, 2026 00:54
@tmat tmat requested a review from a team as a code owner February 20, 2026 00:54
Copilot AI review requested due to automatic review settings February 20, 2026 00:54
@tmat
Copy link
Member Author

tmat commented Feb 20, 2026

@DustinCampbell ptal

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR significantly evolves dotnet-watch to better support modern workflows (file-based apps and polyglot Aspire), while improving project graph loading/build performance and making watch/hotreload logging safer via strongly typed message descriptors.

Changes:

  • Add file-based program support (--file) and plumb ProjectRepresentation through option parsing, launch profile resolution, project graph loading, and build/evaluation paths.
  • Replace/modernize project graph + design-time build infrastructure (multi-root graphs, MSBuild BuildManager parallelization, and updated Roslyn workspace integration).
  • Refactor logging/message infrastructure to use strongly typed MessageDescriptor<TArgs> and adjust tests/assets accordingly.

Reviewed changes

Copilot reviewed 104 out of 104 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs Align virtual project defaults API usage with new target framework representation.
test/dotnet-watch.Tests/Watch/NoRestoreTests.cs Update test context creation for new DotNetWatchContext fields (main/root projects, TFM, build args).
test/dotnet-watch.Tests/Watch/BuildEvaluatorTests.cs Update test context creation for renamed/expanded context fields.
test/dotnet-watch.Tests/TestUtilities/WatchableApp.cs Improve test logging/wait helpers; adjust descriptor matching.
test/dotnet-watch.Tests/TestUtilities/TestRuntimeProcessLauncher.cs Update runtime process launcher factory API usage.
test/dotnet-watch.Tests/TestUtilities/TestProcessRunner.cs Add overridable ProcessRunner for test interception.
test/dotnet-watch.Tests/TestUtilities/TestOptions.cs Update helpers to reflect new option parsing and main-project options flow.
test/dotnet-watch.Tests/TestUtilities/MockFileSetFactory.cs Update MSBuildFileSetFactory construction signature.
test/dotnet-watch.Tests/Process/LaunchSettingsProfileTest.cs Switch launch settings tests to ProjectRepresentation.
test/dotnet-watch.Tests/HotReload/RuntimeProcessLauncherTests.cs Update hot reload launch assertions for new process/running project model and messages.
test/dotnet-watch.Tests/HotReload/CompilationHandlerTests.cs Update compilation handler tests for new graph/workspace update entry points.
test/dotnet-watch.Tests/HotReload/BuildProjectsTests.cs Add tests for building single/multiple projects/files, including solution synthesis behavior.
test/dotnet-watch.Tests/HotReload/ApplyDeltaTests.cs Expand coverage for auto-restart scenarios and message updates; adjust waiting patterns.
test/dotnet-watch.Tests/FileWatcher/FileWatcherTests.cs Minor modernization in test setup.
test/dotnet-watch.Tests/CommandLine/ProgramTests.cs Update program tests for new waiting helpers and updated messages.
test/dotnet-watch.Tests/CommandLine/ProgramTests.GetProjectOptions.cs Add tests for main project selection logic, including --file and argument-based file entry points.
test/dotnet-watch.Tests/CommandLine/LaunchSettingsTests.cs Add coverage for launch settings discovery when using --file.
test/dotnet-watch.Tests/CommandLine/CommandLineOptionsTests.cs Update CLI option parsing tests for --file, -p conflicts, and new launch profile semantics.
test/dotnet-watch.Tests/Build/ProjectGraphFactoryTests.cs Add tests for virtual/regular project graph loading and error reporting.
test/dotnet-watch.Tests/Build/EvaluationTests.cs Update evaluation tests for new MSBuildFileSetFactory signature and graph shape.
test/dotnet-watch.Tests/Browser/BrowserTests.cs Update expected browser-launch message formatting.
test/TestAssets/TestProjects/WatchBrowserLaunchApp/Properties/launchSettings.json Fix dotnetRunMessages type (boolean) for correctness.
test/TestAssets/TestProjects/WatchAspire/WatchAspire.Wasm/Properties/launchSettings.json Fix dotnetRunMessages type (boolean) for correctness.
test/TestAssets/TestProjects/BlazorWasmHosted50/Server/Properties/launchSettings.json Fix dotnetRunMessages type (boolean) for correctness.
test/Microsoft.Extensions.DotNetDeltaApplier.Tests/HotReloadClientTests.cs Update parameter naming to reflect static asset handling semantics.
test/Microsoft.DotNet.HotReload.Watch.Aspire.Tests/DotNetWatchOptionsTests.cs Update Aspire launcher option parsing tests for --file and new project representation.
test/Microsoft.DotNet.HotReload.Test.Utilities/TestAssetExtensions.cs Use Path.Combine for test output directory computation.
src/Microsoft.DotNet.ProjectTools/VirtualProjectBuilder.cs Rename/clarify target framework input; add helper to compute virtual project path.
src/Microsoft.DotNet.ProjectTools/Microsoft.DotNet.ProjectTools.csproj Expose internals to dotnet-watch and its tests.
src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs Pass full target framework moniker rather than version fragment.
src/Cli/Microsoft.DotNet.FileBasedPrograms/Microsoft.DotNet.FileBasedPrograms.projitems Ensure resx designer metadata is set for resource generation.
src/BuiltInTools/dotnet-watch/xlf/Resources.cs.xlf Update localized resources for new/renamed strings.
src/BuiltInTools/dotnet-watch/xlf/Resources.de.xlf Update localized resources for new/renamed strings.
src/BuiltInTools/dotnet-watch/xlf/Resources.es.xlf Update localized resources for new/renamed strings.
src/BuiltInTools/dotnet-watch/xlf/Resources.fr.xlf Update localized resources for new/renamed strings.
src/BuiltInTools/dotnet-watch/xlf/Resources.it.xlf Update localized resources for new/renamed strings.
src/BuiltInTools/dotnet-watch/xlf/Resources.ja.xlf Update localized resources for new/renamed strings.
src/BuiltInTools/dotnet-watch/xlf/Resources.ko.xlf Update localized resources for new/renamed strings.
src/BuiltInTools/dotnet-watch/xlf/Resources.pl.xlf Update localized resources for new/renamed strings.
src/BuiltInTools/dotnet-watch/xlf/Resources.pt-BR.xlf Update localized resources for new/renamed strings.
src/BuiltInTools/dotnet-watch/xlf/Resources.ru.xlf Update localized resources for new/renamed strings.
src/BuiltInTools/dotnet-watch/xlf/Resources.tr.xlf Update localized resources for new/renamed strings.
src/BuiltInTools/dotnet-watch/xlf/Resources.zh-Hans.xlf Update localized resources for new/renamed strings.
src/BuiltInTools/dotnet-watch/xlf/Resources.zh-Hant.xlf Update localized resources for new/renamed strings.
src/BuiltInTools/dotnet-watch/Watch/StaticFileHandler.cs Switch to LoadedProjectGraph mapping for static asset/project lookup.
src/BuiltInTools/dotnet-watch/Watch/MsBuildFileSetFactory.cs Update MSBuild evaluation pipeline to accept TFM/build args and use new graph factory type.
src/BuiltInTools/dotnet-watch/Watch/DotNetWatcher.cs Update graph-root handling and browser launch trigger plumbing.
src/BuiltInTools/dotnet-watch/Watch/BuildEvaluator.cs Use new context fields and updated file change waiting API.
src/BuiltInTools/dotnet-watch/Resources.resx Add/rename resources for new argument conflict errors and invalid path message.
src/BuiltInTools/dotnet-watch/Program.cs Implement main project selection with --file, multi-root handling, and Hot Reload gating for file-based apps.
src/BuiltInTools/dotnet-watch/CommandLine/DotnetWatchCommandDefinition.cs Add --file option and improve option conflict validation.
src/BuiltInTools/dotnet-watch/CommandLine/CommandLineOptions.cs Add FilePath and change launch profile representation to Optional<string?>.
src/BuiltInTools/Watch/Utilities/Option.cs Introduce Optional<T> to represent “unspecified vs default vs none”.
src/BuiltInTools/Watch/Utilities/Disposables.cs Enable async disposal of mixed disposable resources.
src/BuiltInTools/Watch/UI/IReporter.cs Introduce typed message descriptors and typed log-state formatting; expand message set.
src/BuiltInTools/Watch/Process/RunningProject.cs Refactor running project lifetime around new RunningProcess and async disposal.
src/BuiltInTools/Watch/Process/RunningProcess.cs Add dedicated process lifetime/disposal wrapper to address shutdown race conditions.
src/BuiltInTools/Watch/Process/ProjectLauncher.cs Switch to new LoadedProjectGraph lookup and client creation flow.
src/BuiltInTools/Watch/Process/ProcessSpec.cs Require executable and simplify argument handling.
src/BuiltInTools/Watch/Process/ProcessRunner.cs Make runner overridable for tests; adjust typed logging usage.
src/BuiltInTools/Watch/Process/LaunchSettingsProfile.cs Resolve launch settings based on ProjectRepresentation (project or entry point).
src/BuiltInTools/Watch/Process/IRuntimeProcessLauncherFactory.cs Simplify launcher factory contract to Create(ProjectLauncher).
src/BuiltInTools/Watch/Microsoft.DotNet.HotReload.Watch.csproj Remove MSBuild workspace package reference in favor of new Roslyn integration.
src/BuiltInTools/Watch/HotReload/IncrementalMSBuildWorkspace.cs Remove old incremental workspace implementation.
src/BuiltInTools/Watch/HotReload/HotReloadProjectUpdatesBuilder.cs Add builder/accumulator for deciding rebuild/restart/static asset update actions.
src/BuiltInTools/Watch/HotReload/HotReloadEventSource.cs Remove event source perf hooks.
src/BuiltInTools/Watch/FileWatcher/FileWatcher.cs Update waiting helper to support multiple paths.
src/BuiltInTools/Watch/FileWatcher/ChangeKind.cs Add conversion to Roslyn hot reload file change kind.
src/BuiltInTools/Watch/Context/ProjectOptions.cs Replace discrete project path fields with ProjectRepresentation and optional launch profile semantics.
src/BuiltInTools/Watch/Context/DotNetWatchContext.cs Add multi-root graph support and separate main-project vs root-project concepts.
src/BuiltInTools/Watch/Build/ProjectRepresentation.cs Introduce unified representation for project path vs entry point path (file-based apps).
src/BuiltInTools/Watch/Build/ProjectGraphUtilities.cs Move output dir helper to ProjectInstance.
src/BuiltInTools/Watch/Build/ProjectGraphFactory.cs Support multi-root graphs and virtual project instances for file-based programs.
src/BuiltInTools/Watch/Build/ProjectBuildManager.cs Add BuildManager-based parallel build execution for restore/DTB.
src/BuiltInTools/Watch/Build/LoadedProjectGraph.cs Wrap ProjectGraph with mapping and associated collection/logger.
src/BuiltInTools/Watch/Build/FilePathExclusions.cs Update output dir retrieval and typed logging usage.
src/BuiltInTools/Watch/Build/EvaluationResult.cs Rework evaluation to async, parallel restore/DTB, and capture restored instances snapshot.
src/BuiltInTools/Watch/Build/BuildResult.cs Add typed build result container for build manager outputs.
src/BuiltInTools/Watch/Build/BuildRequest.cs Add typed build request container.
src/BuiltInTools/Watch/Build/BuildReporter.cs Make watched-file reporting a static helper; minor API tweaks.
src/BuiltInTools/Watch/Build/BuildNames.cs Add properties used to detect hot reload support constraints (AOT/trim/startup hook support).
src/BuiltInTools/Watch/Browser/BrowserLauncher.cs Split “launching browser” messages by arity; use LaunchProfileName optional semantics.
src/BuiltInTools/Watch/Aspire/AspireServiceFactory.cs Update Aspire launcher to new runtime launcher factory and project representation model.
src/BuiltInTools/Watch/AppModels/WebServerAppModel.cs Update managed client creation and static asset handling flags.
src/BuiltInTools/Watch/AppModels/WebApplicationAppModel.cs Update client creation contract and browser-refresh behavior when managed hot reload unsupported.
src/BuiltInTools/Watch/AppModels/HotReloadAppModel.cs Add managed-agent support checks (TFM/AOT/trim/startup hook) and new creation API.
src/BuiltInTools/Watch/AppModels/DefaultAppModel.cs Respect “managed agent supported” gating and new static asset handling flag.
src/BuiltInTools/Watch/AppModels/BlazorWebAssemblyHostedAppModel.cs Update managed client composition and static asset handling flags.
src/BuiltInTools/Watch/AppModels/BlazorWebAssemblyAppModel.cs Update managed client composition for WASM and new creation API.
src/BuiltInTools/Watch.Aspire/DotNetWatchOptions.cs Add --file support and option conflict validation for Aspire launcher.
src/BuiltInTools/Watch.Aspire/DotNetWatchLauncher.cs Update launcher context/options wiring to new DotNetWatchContext and ProjectRepresentation.
src/BuiltInTools/HotReloadClient/Web/BrowserConnection.cs Rename void-like TCS result type to None.
src/BuiltInTools/HotReloadClient/Web/AbstractBrowserRefreshServer.cs Rename void-like TCS result type to None.
src/BuiltInTools/HotReloadClient/Utilities/None.cs Replace VoidResult with None.
src/BuiltInTools/HotReloadClient/StaticAsset.cs Introduce a dedicated static asset representation type.
src/BuiltInTools/HotReloadClient/Logging/LogEvents.cs Make log events strongly typed and add typed argument extraction.
src/BuiltInTools/HotReloadClient/HotReloadClients.cs Expand to support “no managed agent” mode and separate static asset update paths.
src/BuiltInTools/HotReloadClient/DefaultHotReloadClient.cs Rename “enable static asset updates” flag to “handles static asset updates”.
sdk.slnx Add file-based programs shared project to solution.
eng/Version.Details.xml Add Roslyn MSBuild BuildHost dependency version pin.
eng/Version.Details.props Add build host package version property.
Directory.Packages.props Add central package version for MSBuild BuildHost package.

Comment on lines 8 to 10
using Microsoft.CodeAnalysis.Text;
using static System.Net.Mime.MediaTypeNames;

Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

Microsoft.CodeAnalysis.Text and static System.Net.Mime.MediaTypeNames appear unused in this file. With warnings-as-errors, these unused usings will fail the build; remove them.

Copilot uses AI. Check for mistakes.
Copy link
Member

@DustinCampbell DustinCampbell left a comment

Choose a reason for hiding this comment

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

I'm still reviewing and am about 60 files in.

Copy link
Member

@DustinCampbell DustinCampbell left a comment

Choose a reason for hiding this comment

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

I made it through the rest of the PR. There's lots of good stuff in here. 😄

var task = process.WaitForExitAsync(cancellationToken);

if (timeout is { } timeoutValue)
if (timeout.HasValue)
Copy link
Member

Choose a reason for hiding this comment

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

Out of curiosity, why switch from pattern matching to HasValue + multiple 'Value' accesses?

Copy link
Member Author

Choose a reason for hiding this comment

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

No real reason. I made different changes before and then undid them and didn't undo back to pattern matching.

Comment on lines +28 to +29
var terminationSource = Interlocked.Exchange(ref _terminationSource, null);
ObjectDisposedException.ThrowIf(terminationSource == null, this);
Copy link
Member

Choose a reason for hiding this comment

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

Nice 😄

@tmat
Copy link
Member Author

tmat commented Feb 24, 2026

I made it through the rest of the PR.

Much appreciated! It's a big PR.

@tmat tmat force-pushed the FileBasedPrograms branch from 4bd5c79 to bc05c5d Compare February 24, 2026 04:02
@tmat tmat enabled auto-merge (rebase) February 24, 2026 04:03
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.

2 participants