Skip to content

Add dotnetup "happy path" design proposal - #372

Open
dsplaisted wants to merge 2 commits into
mainfrom
dotnetup-system-integration
Open

Add dotnetup "happy path" design proposal#372
dsplaisted wants to merge 2 commits into
mainfrom
dotnetup-system-integration

Conversation

@dsplaisted

Copy link
Copy Markdown
Member

Proposes how dotnetup makes its managed hive win for SDK and runtime resolution: a near-term change to everywhere mode that prepends the dotnetup dotnet directory before the Program Files entry on the system PATH, and a longer-term user-scoped, source-gated muxer redirect that relocates both SDK and runtime (including dotnet foo.dll).

Proposes how dotnetup makes its managed hive win for SDK and runtime
resolution: a near-term change to `everywhere` mode that prepends the
dotnetup dotnet directory before the Program Files entry on the system
PATH, and a longer-term user-scoped, source-gated muxer redirect that
relocates both SDK and runtime (including `dotnet foo.dll`).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f118977e-1e71-40b0-8045-10f5ab006715
Comment thread accepted/2026/dotnetup/dotnetup-system-integration.md Outdated
Comment on lines +77 to +78
- Make the `dotnetup`-managed hive the SDK that wins for CLI and tools, reliably, after a
simple `dotnetup` action.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should make sure this is:

  • clearly messaged during dotnetup install and in any docs
  • surfaced (with pointers to resolution if possible) in non-happy-path cases - for example, I have some repo that uses local sdk paths, I try dotnetup at some point, later I go back to my repo and it no longer finds the sdk required
  • indicated in general diagnostic info like dotnet --info

Basically, the happy-path requires everything being on-boarded to dotnetup, so I want to make sure we are intentional about the experience in the non-happy-path / transition.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We would want local repo paths to continue to work. The sdk.paths feature should continue to work (and override or be applied after the environment-variable based redirect). Putting a specific version of dotnet on the path shouldi also work as long as we include the "REDIRECT_SOURCE" type environment variable.

It would be good for dotnet --info to include information about the redirection if it applied.


## Relationship to existing mechanisms

- **`global.json` `sdk.paths` / `$host$`**

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Does this mean that the environment variable basically replaces sdk.paths, but everything else in the global.json is respected?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We'd like sdk.paths and everything else in global.json to continue to work. The behavior we'd like is that everything would work the same as if C:\Program Files\dotnet was not on the PATH, and instead the folder specified by the redirect (such as C:\Users\daplaist\AppData\Local\dotnet) were on the PATH instead.

@elinor-fung elinor-fung Jul 27, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

as if C:\Program Files\dotnet was not on the PATH, and instead the folder specified by the redirect (such as C:\Users\daplaist\AppData\Local\dotnet) were on the PATH instead.

So as if it was actually C:\Users\daplaist\AppData\Local\dotnet that was launched? In my mind that means:

  • global.json without sdk.paths: only look in the redirect folder, respecting everything in global.json
    • this means that if the global.json specifies an sdk version that is not in the redirect (but is in the global install), the resolution would fail
  • global.json with sdk.paths: redirect folder replaces $host$ in sdk.paths, if $host$ is not listed in sdk.paths we won't look in the redirect
  • no global.json: only look in redirect folder, use latest sdk found

Does that match your thinking?

SDK/runtime resolution can be confusing enough - I want to make sure we're very explicit about how anything we add interacts with existing features, where it sits in the resolution logic, and if/how much it adds to the complexity.

`PATH`, `dotnetup` today *removes* that entry. This proposal changes that to a durable prepend:

1. Elevate once (the same elevation `dotnetup` already uses to edit the machine-wide `PATH`).
2. **Insert the `dotnetup` dotnet directory into the system `PATH` immediately before the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Does dotnetup do multi-arch today or only the OS architecture?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We don't do multi-arch today but we should think about how the redirect support would interact with multi-arch. I'm not sure if it would, you can't have two different architectures of dotnet on the PATH (or you can, but it doesn't matter since only the first one will apply).

Concretely, the muxer would support the following environment variables:

- `DOTNET_ROOT_REDIRECT_TARGET` - The path of the hive to redirect to
- `DOTNET_ROOT_REDIRECT_SOURCES` - A list of sources to redirect from. This allows the redirect to be restricted to the Program Files muxer, so that other muxers (such as from an unzipped runtime/SDK) are not affected

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this list of sources expected to be something that changes much? Would it be anything other than the global install?

General concern around the source path matching:

  • I assume this would require some sort of canonicalization given the myriad of ways the same path can be specified.
  • different behaviour based on where an install (that is otherwise xcopy-able) is located seems rather confusing.

(I don't have a good solution - just calling it out)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We would expect to only set it to the global install. So theoretically we could have the muxer check its install location to determine whether to apply the redirect without the second environment variable. But it seems probably better (and more testable) to use an environment variable.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wonder if something like a marker file next to dotnet that indicates enabling redirection and is only included in the installation bundle (and not the archives) would make sense. It would avoid path matching. Different acquisition methods would still have different behaviour (when dotnetup has been in play), but it wouldn't change on xcopy to another location.

- **Non-Windows.** The goals are the same on macOS/Linux, but this proposal focuses on the
Windows solution (likely the hardest). Phase 1 is Windows-specific and likely doesn't apply;
Phase 2's redirect may or may not be the right approach there. The cross-platform design
remains to be worked out.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd rather consider this for all platforms (even if Windows is the motivating one).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated this to try to make clear that the muxer feature should apply to all platforms.

access it, so they fall through to the machine-wide install — but an elevated process (or an account such as SYSTEM)
may resolve `dotnet` from that hive, so the wrong user's install can win. This "multi-user oddness"
(accepted for the near term) is why Phase 1 is a bridge; Phase 2 (per-user, no system `PATH`
change) removes it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

removes it

Does that mean a one-time elevation as well?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Phase 2 would have probably include a one-time elevation to install the updated muxer, if it wasn't already installed in Program Files.

@elinor-fung

Copy link
Copy Markdown
Member

cc @richlander

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