Skip to content

Commit ccdab30

Browse files
authored
Warn about common run-file pitfalls (#53833)
1 parent 4b377c5 commit ccdab30

17 files changed

Lines changed: 603 additions & 19 deletions

src/Cli/dotnet/Commands/CliCommandStrings.resx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,22 @@ Tool '{1}' (version '{2}') was successfully installed. Entry is added to the man
964964
<data name="RunCommandExceptionNoProjects" xml:space="preserve">
965965
<value>Couldn't find a project to run. Ensure a project exists in {0}, or pass the path to the project using {1}.</value>
966966
</data>
967+
<data name="RunCommandWarningFileArgumentPassedToProject" xml:space="preserve">
968+
<value>Warning: '{0}' appears to be a file-based app but was passed as an argument to the project '{1}'. To run it as a file-based app, use 'dotnet run --file {0}'. To pass it as an application argument, use 'dotnet run -- {0}' to suppress this warning.</value>
969+
<comment>{0} is the file path argument. {1} is the project file path.{Locked="dotnet run --file"}{Locked="dotnet run --"}</comment>
970+
</data>
971+
<data name="WarningFileArgumentPassedToMSBuild" xml:space="preserve">
972+
<value>Warning: '{0}' appears to be a file-based app but was treated as an MSBuild argument. To treat it as a file-based app, use 'dotnet {1} {0}'.</value>
973+
<comment>{0} is the file path argument. {1} is the command name (e.g. build, clean, publish).{Locked="dotnet"}</comment>
974+
</data>
975+
<data name="WarningCsFileArgumentPassedToMSBuild" xml:space="preserve">
976+
<value>Warning: '{0}' looks like a file-based app but the file was not found, and it was treated as an MSBuild argument.</value>
977+
<comment>{0} is the .cs file path argument.</comment>
978+
</data>
979+
<data name="RunCommandWarningCsFileArgumentPassedToProject" xml:space="preserve">
980+
<value>Warning: '{0}' looks like a file-based app but the file was not found, and it was passed as an argument to the project '{1}'. To pass it as an application argument, use 'dotnet run -- {0}' to suppress this warning.</value>
981+
<comment>{0} is the .cs file path argument. {1} is the project file path.{Locked="dotnet run --"}</comment>
982+
</data>
967983
<data name="RunCommandExceptionUnableToRun" xml:space="preserve">
968984
<value>Unable to proceed with project '{0}'.
969985
Ensure you have a runnable project type.

src/Cli/dotnet/Commands/CommandFactory.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.DotNet.Cli.CommandLine;
66
using Microsoft.DotNet.Cli.Commands.Run;
77
using Microsoft.DotNet.Cli.Utils;
8+
using Microsoft.DotNet.Cli.Utils.Extensions;
89
using Microsoft.DotNet.ProjectTools;
910

1011
namespace Microsoft.DotNet.Cli.Commands;
@@ -39,6 +40,26 @@ internal static CommandBase CreateVirtualOrPhysicalCommand(
3940
}
4041
else
4142
{
43+
// Warn if any argument looks like a file-based program entry point but we're falling back to MSBuild.
44+
// This can happen when extra positional arguments prevent the single-arg file-based path from being taken,
45+
// or when a .cs file doesn't exist (so IsValidEntryPointPath returns false).
46+
foreach (var candidate in nonBinLogArgs)
47+
{
48+
if (VirtualProjectBuilder.IsValidEntryPointPath(candidate))
49+
{
50+
Reporter.Error.WriteLine(
51+
string.Format(CliCommandStrings.WarningFileArgumentPassedToMSBuild, candidate, commandDefinition.Name).Yellow());
52+
break;
53+
}
54+
55+
if (candidate.EndsWith(".cs", StringComparison.OrdinalIgnoreCase))
56+
{
57+
Reporter.Error.WriteLine(
58+
string.Format(CliCommandStrings.WarningCsFileArgumentPassedToMSBuild, candidate).Yellow());
59+
break;
60+
}
61+
}
62+
4263
var msbuildArgs = MSBuildArgs.AnalyzeMSBuildArguments([.. forwardedArgs, .. args], [.. optionsToUseWhenParsingMSBuildFlags]);
4364
msbuildArgs = transformer?.Invoke(msbuildArgs) ?? msbuildArgs;
4465
return createPhysicalCommand(msbuildArgs, msbuildPath);

src/Cli/dotnet/Commands/Run/RunCommand.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,41 @@ public static RunCommand FromParseResult(ParseResult parseResult)
852852
ref args,
853853
out string? entryPointFilePath);
854854

855+
// Warn if an argument looks like a file-based program entry point but we're falling back to project-based run.
856+
// This helps users who accidentally run `dotnet run file.cs` in a directory containing a project file.
857+
// Do not warn if --project or --file was explicitly specified.
858+
// Only consider arguments that appear before '--' in the command line.
859+
if (projectFilePath is not null && projectOption is null && fileOption is null && !readCodeFromStdin)
860+
{
861+
var argValuesBeforeDoubleDash = parseResult.Tokens
862+
.TakeWhile(static t => t.Type != TokenType.DoubleDash)
863+
.Where(static t => t.Type == TokenType.Argument)
864+
.Select(static t => t.Value)
865+
.ToHashSet();
866+
867+
foreach (var arg in args)
868+
{
869+
if (!argValuesBeforeDoubleDash.Contains(arg))
870+
{
871+
continue;
872+
}
873+
874+
if (VirtualProjectBuilder.IsValidEntryPointPath(arg))
875+
{
876+
Reporter.Error.WriteLine(
877+
string.Format(CliCommandStrings.RunCommandWarningFileArgumentPassedToProject, arg, projectFilePath).Yellow());
878+
break;
879+
}
880+
881+
if (arg.EndsWith(".cs", StringComparison.OrdinalIgnoreCase))
882+
{
883+
Reporter.Error.WriteLine(
884+
string.Format(CliCommandStrings.RunCommandWarningCsFileArgumentPassedToProject, arg, projectFilePath).Yellow());
885+
break;
886+
}
887+
}
888+
}
889+
855890
bool noBuild = parseResult.HasOption(definition.NoBuildOption);
856891
string launchProfile = parseResult.GetValue(definition.LaunchProfileOption) ?? string.Empty;
857892

src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf

Lines changed: 21 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf

Lines changed: 21 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf

Lines changed: 21 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)