Skip to content

Add support for dotnet file.cs (without explicit run subcommand) #48387

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 13, 2025

Conversation

jjonescz
Copy link
Member

@jjonescz jjonescz commented Apr 11, 2025

Resolves #49202.

@ghost ghost added Area-CLI untriaged Request triage from a team member labels Apr 11, 2025
@jjonescz jjonescz added Area-run-file Items related to the "dotnet run <file>" effort and removed Area-CLI labels Apr 11, 2025
@vrubleg
Copy link

vrubleg commented May 25, 2025

Please make sure that .csx file extension is also allowed. The .csx file extension was used for C# scripts for ages. It was possible to execute those by csi.exe from the MSBuild distribution, and dotnet run looks like a great way to move forward.

Having a separate extension makes clear that it's the entry point and can be executed directly. Some people might even register .csx to be executed directly without prepending dotnet run (that is possible to do with shebang on Linux).

@alefranz
Copy link

alefranz commented Jun 1, 2025

I think this should also default to the Release configuration

@DamianEdwards
Copy link
Member

I think this should also default to the Release configuration

@alefranz yeah I think I agree with this

@DamianEdwards
Copy link
Member

@vrubleg .csx file execution is distinct from what we're doing with dotnet run file.cs and is used to denote the dialect of C# executed by C# interactive, which has different capabilities and execution semantics that aren't fully compatible with regular C#, i.e. it doesn't map properly to projects and thus can introduce issues with dotnet project convert app.cs. For this reason we have no plan to support .csx as part of this effort.

@jaredpar jaredpar added this to the 10.0.1xx milestone Jun 10, 2025
@jjonescz jjonescz marked this pull request as ready for review June 10, 2025 13:23
@Copilot Copilot AI review requested due to automatic review settings June 10, 2025 13:23
@jjonescz jjonescz requested review from tmat, arunchndr and a team as code owners June 10, 2025 13:23
Copy link
Contributor

@Copilot 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

Adds the ability to invoke a C# source file directly with dotnet file.cs, implicitly routing to dotnet run file.cs and defaulting to the Release configuration.

  • Injects the run subcommand and -p:Configuration=Release when the first argument is a .cs file.
  • Reorders property/configuration options so user-specified configurations override the default.
  • Provides integration tests and updates documentation for the new dotnet file.cs shortcut.

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/dotnet.Tests/CommandTests/Run/RunFileTests.cs Added an integration test for invoking dotnet file.cs with default and overridden configs.
test/dotnet-watch.Tests/CommandLineOptionsTests.cs Updated expected ordering of property and framework build arguments in watch tests.
src/Cli/dotnet/Program.cs Detects a .cs entry-point file and prepends run with Release configuration.
src/Cli/dotnet/Commands/Run/RunCommandParser.cs Moved PropertyOption ahead of ConfigurationOption to let -c/--configuration override.
documentation/general/dotnet-run-file.md Added description and shebang examples for the dotnet file.cs shortcut.
Comments suppressed due to low confidence (2)

src/Cli/dotnet/Commands/Run/RunCommandParser.cs:82

  • Fix typo in comment: change 'deafult' to 'default'.
// `-p:Configuration=Release` when `dotnet file.cs` is executed where we want the Release config to be deafult

src/Cli/dotnet/Program.cs:131

  • Add unit tests covering ProcessArgs behavior for edge cases (e.g., uppercase extensions, absolute paths, non-existent files) to ensure the implicit run injection is robust.
? Parser.Instance.Parse(["run", "-p:Configuration=Release", .. args])

@RikkiGibson RikkiGibson self-assigned this Jun 10, 2025
@@ -64,6 +64,9 @@ For example, the remaining command-line arguments after the first argument (the
(except for the arguments recognized by `dotnet run` unless they are after the `--` separator)
and working directory is not changed (e.g., `cd /x/ && dotnet run /y/file.cs` runs the program in directory `/x/`).

`dotnet path.cs` is a shortcut for `dotnet run -p:Configuration=Release path.cs` provided that `path.cs` exists and has `.cs` file extension.
Because of the `-p:Configuration=Release` option, `dotnet path.cs` builds and runs the program with Release configuration by default unlike `dotnet run path.cs`.
Copy link
Member

@RikkiGibson RikkiGibson Jun 10, 2025

Choose a reason for hiding this comment

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

#49202 (comment) indicates that #!/usr/bin/env dotnet is the only supported way to run via shebang. So do we want to couple these decisions together? If user wants to run their script as ./myapp.cs, they need to run in release mode?

It looks like when the program contains #:property Configuration=Debug, dotnet app.cs will respect that. So that might be reasonable. Though, I think that is also different than passing -p:Configuration=Release for a dotnet build, I thought that a property value on command line normally "wins" over options in the project file. I might have that wrong. If there is a difference there it would be good to document it.

Copy link
Member Author

Choose a reason for hiding this comment

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

I thought that a property value on command line normally "wins" over options in the project file.

That's correct and it's what happens, I will add a test.

Copy link
Member Author

@jjonescz jjonescz Jun 11, 2025

Choose a reason for hiding this comment

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

So do we want to couple these decisions together? If user wants to run their script as ./myapp.cs, they need to run in release mode?

Good question. @DamianEdwards? I wouldn't be against removing the implicit -c Release as (1) it might be confusing that it behaves differently from dotnet run, (2) users can add #:property Configuration Release to their scripts to achieve the behavior, (3) as Rikki discovered, it's impossible to overwrite the configuration with argumentless executable.

Copy link
Member

Choose a reason for hiding this comment

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

Yep that's fair. This is kinda a philosophical question. If all this maps to dotnet run then the default configuration should be Debug. To change it, folks can use a property directive, implicit build file, or environment variable, all of which should work even in the shebang single argument case.

Let's keep it all aligned as Configuration=Debug.

Copy link

@vrubleg vrubleg Jun 12, 2025

Choose a reason for hiding this comment

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

Maybe it makes sense to make dotnet run always use Release by default no matter what kind of project it runs? It sounds like the most desirable default in this case. If somebody needs to run with Debug config for some reason, a new command dotnet debug could be introduced, which would be equal to dotnet run with the only difference that it uses Debug configuration by default. Or a short argument --debug for the dotnet run would also be fine and easy to remember. The -p:Configuration=Debug or -p:Configuration=Release are too long and inconvenient for something that you are supposed to quickly type and execute in command line.

Copy link
Member Author

Choose a reason for hiding this comment

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

The -p:Configuration=Debug or -p:Configuration=Release are too long and inconvenient for something that you are supposed to quickly type and execute in command line.

There are shorter versions: -c Debug and -c Release

Choose a reason for hiding this comment

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

you made me dream for a second 🥲 I still believe that by default it should be "fast" for this scenario.
It's fair to not conflate it with this PR, but I think it would be worth to reconsider it before the single file support is shipped.

Copy link
Member

Choose a reason for hiding this comment

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

There's almost no chance of us changing the default configuration for dotnet run as it's been Debug forever and impacts so many experiences in the developer inner-loop (but of course just saying that out load means it's more likely to happen lol). I don't believe debug vs. configuration changes compile and startup time significantly enough for it to be of concern WRT single file app launch time. The far bigger factors are cold-start time of MSBuild and MSBuild operations themselves (aka building) for which we have intend to do other work. For throughput/execution performance it's true that debug vs. release can make a large difference but not for the scenarios we primarily envisage run-file to be used for, and in the cases where it really does matter for a specific app, it's easy enough to add the directive to the file or pass the -c Release command line argument.

@jjonescz
Copy link
Member Author

@MiYanni for a review, thanks

@jaredpar jaredpar merged commit a0515ab into dotnet:main Jun 13, 2025
30 checks passed
@jjonescz jjonescz deleted the sprint-norun branch June 13, 2025 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-run-file Items related to the "dotnet run <file>" effort untriaged Request triage from a team member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Simplify dotnet run file without run
7 participants