Skip to content

Dotnet Tool Integration#13168

Merged
davidfowl merged 35 commits intodotnet:mainfrom
afscrome:dotnettool
Jan 15, 2026
Merged

Dotnet Tool Integration#13168
davidfowl merged 35 commits intodotnet:mainfrom
afscrome:dotnettool

Conversation

@afscrome
Copy link
Contributor

@afscrome afscrome commented Nov 24, 2025

Description

This Pr contains a dotnet tool resource type, currently marked as experimental. (Based on my initial work, and some of copilots work from #13169.).

Fixes #13077

It builds upon the Executable resource ultimately calling into dotnet tool exec - similar to how ProjectResource builds on top of ExecutableResource, and calls dotnet run or dotnet watch. Although I've avoided teaching dcp or the application orchestrator anything specific about dotnet tools.

Basic Use:

builder.AddDotnetTool("tool", "dotnet-ef")
            .WithArgs("--help");

With some helper methods on the resource builder for arguments on dotnet tool exec

.WithToolVersion("9.0.1");
.WithToolPrerelease();
.WithToolSource("./fake-package-feed");
.WithToolIgnoreExistingFeeds();
.WithToolIgnoreFailedSources();

Which are just wrappers over the DotnetToolAnnotation attached to the resource.

The resource sets custom resource properties so the dashboard renders the Source column for tools more natively, without focusing on the implementation details of dotnet tool exec
Without:
image

After:
image

Tool have a dedicated resource type, so you can filter to just tools
image

And also includes some tool specific properties. (Although these are only visible by choosing "show all properties"
image

image

Limitations / Known Issues

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No
  • Does the change require an update in our Aspire docs?

@github-actions
Copy link
Contributor

github-actions bot commented Nov 24, 2025

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 13168

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 13168"

@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Nov 24, 2025
@afscrome afscrome changed the title Dotnettool Dotnet Tool Integration Nov 24, 2025
@afscrome afscrome mentioned this pull request Nov 24, 2025
1 task
afscrome and others added 16 commits November 24, 2025 19:59
…ence

Co-authored-by: davidfowl <95136+davidfowl@users.noreply.github.com>
…ort allocation

- Changed app URLs from 18001/18002 to 16179/16180 (standard app port range)
- Updated OTLP endpoints from 18003/18005 to 17119/17120 (standard OTLP range)
- Added MCP endpoints 18036/18037 (standard MCP range)
- Updated Resource Service endpoints to match OTLP endpoints
- Removed launchBrowser from generate-manifest profile for consistency

Co-authored-by: davidfowl <95136+davidfowl@users.noreply.github.com>
- Removed DotnetToolInstaller.cs (leftover from dotnet tool install approach)
- Created new test project Aspire.Hosting.DotnetTool.Tests with 22 tests
- All tests pass and validate AddDotnetTool extension methods
- Tests cover: basic usage, version specs, prerelease, custom sources, args, and manifest generation
- Added using statements to playground files (needed for test linking)
- Fixed DotnetToolResource to use "." as working directory (fixes manifest generation)
- Added test project to solution file in alphabetical order

Co-authored-by: davidfowl <95136+davidfowl@users.noreply.github.com>
Updated `ResourceSnapshotBuilder` to not override any custom resource types a consumer may have set.

Updated `ApplicationOrchestrator` to also not set the resource type - we don't need two places in Aspire core setting the ResourceType
The implementation works, but isnt' great as it fights with DCP a lot.
x.Args.Add("--");
}

static async Task StartSourceFixer(T resource, InitializeResourceEvent evt, CancellationToken ct)
Copy link
Contributor Author

@afscrome afscrome Dec 3, 2025

Choose a reason for hiding this comment

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

This method is a hack and a half.

To make the source column show just the tool args, and not the internals of the dotnet command run, we need to set KnownProperties.Executable.Path and KnownProperties.Resource.AppArgs. The latter in turn also requires messing with KnownProperties.Resource.AppArgsSensitivity to ensure secrets are properly redacted.

However dcp will continually overwrite those properties every time an update occurs, so we need to respond to those and restore our values.

return previous with
{
ResourceType = KnownResourceTypes.Executable,
State = state,
ExitCode = executable.Status?.ExitCode,
Properties = previous.Properties.SetResourcePropertyRange([
new(KnownProperties.Executable.Path, executable.Spec.ExecutablePath),
new(KnownProperties.Executable.WorkDir, executable.Spec.WorkingDirectory),
new(KnownProperties.Executable.Args, executable.Status?.EffectiveArgs ?? []) { IsSensitive = true },
new(KnownProperties.Executable.Pid, executable.Status?.ProcessId),
new(KnownProperties.Resource.AppArgs, launchArguments?.Args) { IsSensitive = launchArguments?.IsSensitive ?? false },
new(KnownProperties.Resource.AppArgsSensitivity, launchArguments?.ArgsAreSensitive) { IsSensitive = launchArguments?.IsSensitive ?? false },
]),
EnvironmentVariables = environment,
CreationTimeStamp = executable.Metadata.CreationTimestamp?.ToUniversalTime(),
StartTimeStamp = executable.Status?.StartupTimestamp?.ToUniversalTime(),
StopTimeStamp = executable.Status?.FinishTimestamp?.ToUniversalTime(),
Urls = urls,
Relationships = relationships
};

So this method tries to respond to any update from DCP, and undo DCP's changes.

Enhances Aspire to treat dotnet tool resources as first-class citizens.
- Adds KnownResourceTypes.Tool and updates DotnetToolResource to use it.
- Sets tool package ID as the resource "Source" for dashboard clarity.
- Adds IsTool and TryGetToolPackage extensions for resource model.
- Updates dashboard to display tool package as source.
- Refines argument handling: only tool-specific args are shown in dashboard, full args used for execution.
- Refactors DotnetToolResourceExtensions and removes dashboard update workaround.
- Removed unused `IResourceAnnotation` from AppLaunchArgumentAnnotation.
- Adds and updates tests for tool resource handling.
- Improves diagnostics with DebuggerDisplay and code cleanups.
Copilot AI review requested due to automatic review settings January 1, 2026 20:52
@afscrome afscrome requested a review from mitchdenny as a code owner January 1, 2026 20:52
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 introduces experimental support for .NET tool resources in Aspire, allowing developers to run .NET global tools (like dotnet-ef, dotnet-dump, etc.) as Aspire resources using dotnet tool exec. This feature addresses the need for tool acquisition and execution without manual installation steps, building on the existing ExecutableResource infrastructure.

Key Changes:

  • New DotnetToolResource and DotnetToolAnnotation types for representing .NET tools as first-class resources
  • Extension methods for configuring tool version, prerelease support, custom NuGet sources, and feed behavior
  • Dashboard integration showing tools with a dedicated resource type and custom "Source" column display
  • Comprehensive test coverage including unit tests and functional tests

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 20 comments.

Show a summary per file
File Description
src/Aspire.Hosting/ApplicationModel/DotnetToolResource.cs New resource class representing .NET tool resources, inheriting from ExecutableResource
src/Aspire.Hosting/ApplicationModel/DotnetToolAnnotation.cs New annotation class containing tool configuration (package ID, version, sources, flags)
src/Aspire.Hosting/DotnetToolResourceExtensions.cs Extension methods for adding and configuring .NET tool resources with fluent API
src/Aspire.Hosting/Dcp/DcpExecutor.cs Modified argument handling to distinguish between executable args and display args for tools
src/Aspire.Hosting/Dcp/ResourceSnapshotBuilder.cs Updated to preserve ResourceType set via WithInitialState instead of overwriting
src/Aspire.Hosting/Orchestrator/ApplicationOrchestrator.cs Removed ResourceType assignments as it's now set earlier via WithInitialState
src/Aspire.Hosting/ApplicationModel/AppLaunchArgumentAnnotation.cs Removed IResourceAnnotation interface (internal implementation detail)
src/Shared/Model/KnownResourceTypes.cs Added "Tool" resource type constant
src/Shared/Model/KnownProperties.cs Added tool-specific properties (Package, Version, ExecArgs)
src/Aspire.Dashboard/Model/ResourceViewModelExtensions.cs Added IsTool() and TryGetToolPackage() extension methods
src/Aspire.Dashboard/Model/ResourceSourceViewModel.cs Updated source display logic to show tool package name in Source column
tests/Aspire.Hosting.DotnetTool.Tests/AddDotnetToolTests.cs Comprehensive unit tests covering all configuration options and manifest generation
tests/Aspire.Hosting.DotnetTool.Tests/DotnetToolFunctionalTests.cs.cs Functional tests verifying tool execution with successful and failed scenarios
tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs Added test for tool argument handling in DCP executor
tests/Aspire.Hosting.DotnetTool.Tests/Aspire.Hosting.DotnetTool.Tests.csproj New test project for .NET tool resource tests
playground/DotnetTool/DotnetTool.AppHost/* Sample AppHost demonstrating various tool configurations and edge cases
Aspire.slnx Added references for new test project and playground app

Comment on lines +19 to +25
/// <summary>
/// Adds a .NET tool resource to the distributed application builder.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource.</param>
/// <param name="packageId">The package id of the tool.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
Copy link

Copilot AI Jan 1, 2026

Choose a reason for hiding this comment

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

According to the XML documentation guidelines, public API extension methods should include an example showing practical usage. Consider adding an example section showing how to use AddDotnetTool.

Copilot generated this review using guidance from repository custom instructions.
afscrome and others added 4 commits January 1, 2026 21:12
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Member

@davidfowl davidfowl left a comment

Choose a reason for hiding this comment

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

LGTM - clean implementation following Aspire patterns. Experimental flag is appropriate for new API.

@davidfowl davidfowl merged commit cd3b5b9 into dotnet:main Jan 15, 2026
289 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the 13.2 milestone Jan 15, 2026
@davidfowl
Copy link
Member

Thanks for the contribution! This is a great addition to Aspire. 🎉

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dotnet Tool Integration

4 participants