Skip to content

Extend the dotnet run command discovery protocol to be settable by a Target instead of just Evaluation #42155

@baronfel

Description

@baronfel

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

When running a project, dotnet run has a protocol that it implements to determine how to run the project:

  1. Detect the project that should be run
  2. Determine the 'launch settings' and profile that will be applied to the project
  3. Build the project if required
  4. Determine the RunCommand/RunArguments/RunWorkingDirectory for the project to create an executable ICommand
  5. Apply 'launch settings' to the ICommand
  6. Invoke the ICommand

In a graphic this looks like:

sequenceDiagram
  participant dotnet as dotnet CLI
  participant project as myproj.proj
  participant exe as RunCommand
  dotnet->>dotnet: detect project to run
  dotnet->>dotnet: read launch settings from file and pick launch profile
  dotnet->>project: build project (if required)
  dotnet->>project: evaluate project to get run settings
  dotnet->>exe: create process to spawn from run settings
  dotnet->>exe: apply launch profile to process
  dotnet->>exe: spawn process
  dotnet->>exe: run process to completion
Loading

This process relies on MSBuild evaluation to determine the RunCommand/RunArguments/RunWorkingDirectory, which means that these values can only be set during evaluation - no code or logic can run to influence their values. This can be highly limiting and means that use cases that need to run some dynamic logic to determine a value to put in the RunWorkingDirectory, for example, cannot be safely run.

Describe the solution you'd like

We should have an opt-in protocol that would allow dotnet run to invoke a target to get the RunCommand/RunArguments/RunWorkingDirectory data. This target should be public and documented and would update step 4 above as follows:

  1. Determine the RunCommand/RunArguments/RunWorkingDirectory for the project to create an executable ICommand
    a. if the project supports a ComputeRunCommand Target, then run that target and read the RunCommand/RunArguments/RunWorkingDirectory after target execution
    b. otherwise read the same properties just after evaluation, as is done today
    c. when called, this target would be passed all of the same MSBuild properties as applied to the implicit build in step 3

In a graphic this would look like:

sequenceDiagram
  participant dotnet as dotnet CLI
  participant project as myproj.proj
  participant exe as RunCommand
  dotnet->>dotnet: detect project to run
  dotnet->>dotnet: read launch settings from file and pick launch profile
  dotnet->>project: build project (if required)
  dotnet->>project: evaluate project
  dotnet->>project: invoke target to get run settings
  project->>dotnet: return run settings
  dotnet->>exe: create process to spawn from run settings
  dotnet->>exe: apply launch profile to process
  dotnet->>exe: spawn process
  dotnet->>exe: run process to completion
Loading

Run Command Protocol

This new target would need to define its protocol

  • Name
  • Dependencies - what is a reasonable dependency chain for this Target? How do projects like MAUI change this dependency chain?
  • Outputs - should the target set properties, or should we take the opportunity to make a different representation

Opting-in

Projects would need to opt into the new behavior - the SDK currently computes the values here and so could change this for SDK-style projects as a default. Should there be a property-based opt-in, or should we just start doing this wholesale since the CLI and SDK targets change in lockstep?

Use cases like Azure Functions or MAUI may want to override the generation and so could override the target or set up a BeforeTargets, etc.

Compatibility

  • The MSBuild Run target defined in the SDK should have a dependency on the new target if defined.
  • The dotnet watch command currently uses the RunCommand/RunArguments/RunWorkingDirectory as inputs to GenerateWatchList - it will need to become aware of this target if necessary as well.
  • We should add a new ProjectCapability signalling that a Project uses this new mechanism, so that IDEs have a flag for behavior.
  • The new Target could be integrated into the Design-Time Build dependency chain.

Binlogs

We would to to ensure that if a binlog was requested that the configured binlog logger also applied to this new target, not just the implicit build + project evaluation for Run argument discovery

Additional context

@captainsafia for Aspire
@fabiocav for Functions
@jonathanpeppers for MAUI
@danroth27 for web
@tmat for watch
@tmeschter for project-system

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions