From bed6756df98e6ab28062a1254613cc7cf2074b54 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:28:23 +0000 Subject: [PATCH 1/5] Initial plan From 1a724042d780dfbe57542c0644292b4ee5547485 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:36:30 +0000 Subject: [PATCH 2/5] Initial plan for setting EnableDefaultEmbeddedResourceItems and EnableDefaultNoneItems to false for file-based apps Co-authored-by: jjonescz <3669664+jjonescz@users.noreply.github.com> --- .../src/RulesMissingDocumentation.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/RulesMissingDocumentation.md b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/RulesMissingDocumentation.md index c5820fde91ae..75e0f77588e2 100644 --- a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/RulesMissingDocumentation.md +++ b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/RulesMissingDocumentation.md @@ -2,7 +2,3 @@ Rule ID | Missing Help Link | Title | --------|-------------------|-------| -CA1873 | | Avoid potentially expensive logging | -CA1874 | | Use 'Regex.IsMatch' | -CA1875 | | Use 'Regex.Count' | -CA2023 | | Invalid braces in message template | From 00e8f50acc9db4d7a48988e12c78da5194790097 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:46:24 +0000 Subject: [PATCH 3/5] Set EnableDefaultEmbeddedResourceItems and EnableDefaultNoneItems to false for file-based apps with default SDK Co-authored-by: jjonescz <3669664+jjonescz@users.noreply.github.com> --- .../Run/VirtualProjectBuildingCommand.cs | 12 ++++++++ .../CommandTests/Run/RunFileTests.cs | 30 ++++++++++++++----- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs b/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs index bdd97d2402b7..a833384dcfee 100644 --- a/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs +++ b/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs @@ -1191,6 +1191,18 @@ public static void WriteProjectFile( true """); + // Only set these to false when using the default SDK with no additional SDKs + // to avoid including .resx and other files that are typically not expected in simple file-based apps. + // When other SDKs are used (e.g., Microsoft.NET.Sdk.Web), keep the default behavior. + bool usingOnlyDefaultSdk = firstSdkName == "Microsoft.NET.Sdk" && sdkDirectives.Count() <= 1; + if (usingOnlyDefaultSdk) + { + writer.WriteLine($""" + false + false + """); + } + // Write default properties before importing SDKs so they can be overridden by SDKs // (and implicit build files which are imported by the default .NET SDK). foreach (var (name, value) in DefaultProperties) diff --git a/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs b/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs index db3696b077ec..0b0455c392df 100644 --- a/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs +++ b/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs @@ -1363,7 +1363,7 @@ public void Verbosity_CompilationDiagnostics() } /// - /// Default projects include embedded resources by default. + /// File-based projects using the default SDK do not include embedded resources by default. /// [Fact] public void EmbeddedResource() @@ -1372,6 +1372,21 @@ public void EmbeddedResource() File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), s_programReadingEmbeddedResource); File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx); + // By default, with the default SDK, embedded resources are not included + new DotnetCommand(Log, "run", "Program.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass() + .And.HaveStdOut(""" + Resource not found + """); + + // This behavior can be overridden to enable embedded resources. + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), $""" + #:property EnableDefaultEmbeddedResourceItems=true + {s_programReadingEmbeddedResource} + """); + new DotnetCommand(Log, "run", "Program.cs") .WithWorkingDirectory(testInstance.Path) .Execute() @@ -1380,9 +1395,9 @@ public void EmbeddedResource() [MyString, TestValue] """); - // This behavior can be overridden. + // When using a non-default SDK, embedded resources are included by default File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), $""" - #:property EnableDefaultEmbeddedResourceItems=false + #:sdk Microsoft.NET.Sdk.Web {s_programReadingEmbeddedResource} """); @@ -1391,7 +1406,7 @@ public void EmbeddedResource() .Execute() .Should().Pass() .And.HaveStdOut(""" - Resource not found + [MyString, TestValue] """); } @@ -1402,8 +1417,6 @@ Resource not found [Theory, CombinatorialData] public void EmbeddedResource_AlongsideProj([CombinatorialValues("sln", "slnx", "csproj", "vbproj", "shproj", "proj")] string ext) { - bool considered = ext is "sln" or "slnx" or "csproj"; - var testInstance = _testAssetsManager.CreateTestDirectory(); File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), s_programReadingEmbeddedResource); File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx); @@ -1411,11 +1424,12 @@ public void EmbeddedResource_AlongsideProj([CombinatorialValues("sln", "slnx", " // Up-to-date check currently doesn't support default items, so we need to pass --no-cache // otherwise other runs of this test theory might cause outdated results. + // With the default SDK, embedded resources are not included by default regardless of project files new DotnetCommand(Log, "run", "--no-cache", "--file", "Program.cs") .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Pass() - .And.HaveStdOut(considered ? "Resource not found" : "[MyString, TestValue]"); + .And.HaveStdOut("Resource not found"); } [Fact] @@ -3151,6 +3165,7 @@ public void UpToDate_DefaultItems(bool optOut) var testInstance = _testAssetsManager.CreateTestDirectory(); var code = $""" {(optOut ? "#:property FileBasedProgramCanSkipMSBuild=false" : "")} + #:property EnableDefaultEmbeddedResourceItems=true {s_programReadingEmbeddedResource} """; File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), code); @@ -3215,6 +3230,7 @@ public void UpToDate_DefaultItems_CscOnly_AfterMSBuild(bool optOut) var code = $""" #:property Configuration=Release {(optOut ? "#:property FileBasedProgramCanSkipMSBuild=false" : "")} + #:property EnableDefaultEmbeddedResourceItems=true {s_programReadingEmbeddedResource} """; File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), code); From 9b90303cfe96677b2a0e7ccc0c982f0d6d6db867 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Tue, 4 Nov 2025 13:28:22 +0100 Subject: [PATCH 4/5] Revert unrelated change to RulesMissingDocumentation.md --- .../src/RulesMissingDocumentation.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/RulesMissingDocumentation.md b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/RulesMissingDocumentation.md index 75e0f77588e2..c5820fde91ae 100644 --- a/src/Microsoft.CodeAnalysis.NetAnalyzers/src/RulesMissingDocumentation.md +++ b/src/Microsoft.CodeAnalysis.NetAnalyzers/src/RulesMissingDocumentation.md @@ -2,3 +2,7 @@ Rule ID | Missing Help Link | Title | --------|-------------------|-------| +CA1873 | | Avoid potentially expensive logging | +CA1874 | | Use 'Regex.IsMatch' | +CA1875 | | Use 'Regex.Count' | +CA2023 | | Invalid braces in message template | From 14d24f772e545b79a233074051947625053909fd Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Tue, 4 Nov 2025 13:58:12 +0100 Subject: [PATCH 5/5] Improve code, tests, and docs --- documentation/general/dotnet-run-file.md | 3 + .../Run/VirtualProjectBuildingCommand.cs | 11 +-- .../Convert/DotnetProjectConvertTests.cs | 12 +++- .../CommandTests/Run/RunFileTests.cs | 69 ++++++++----------- 4 files changed, 49 insertions(+), 46 deletions(-) diff --git a/documentation/general/dotnet-run-file.md b/documentation/general/dotnet-run-file.md index 41bb96b5f6a2..a14132092ee1 100644 --- a/documentation/general/dotnet-run-file.md +++ b/documentation/general/dotnet-run-file.md @@ -56,6 +56,9 @@ Additionally, the implicit project file has the following customizations: in case there is a project or solution in the same directory as the file-based app. This ensures that items from nested projects and artifacts are not included by the app. + - `EnableDefaultEmbeddedResourceItems` and `EnableDefaultNoneItems` properties are set to `false` if the default SDK (`Microsoft.NET.Sdk`) is being used. + This avoids including files like `./**/*.resx` in simple file-based apps where users usually don't expect that. + ## Grow up When file-based programs reach an inflection point where build customizations in a project file are needed, diff --git a/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs b/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs index a833384dcfee..fe79a333d695 100644 --- a/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs +++ b/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs @@ -1156,6 +1156,7 @@ public static void WriteProjectFile( var packageDirectives = directives.OfType(); var projectDirectives = directives.OfType(); + const string defaultSdkName = "Microsoft.NET.Sdk"; string firstSdkName; string? firstSdkVersion; @@ -1167,7 +1168,7 @@ public static void WriteProjectFile( } else { - firstSdkName = "Microsoft.NET.Sdk"; + firstSdkName = defaultSdkName; firstSdkVersion = null; } @@ -1194,7 +1195,7 @@ public static void WriteProjectFile( // Only set these to false when using the default SDK with no additional SDKs // to avoid including .resx and other files that are typically not expected in simple file-based apps. // When other SDKs are used (e.g., Microsoft.NET.Sdk.Web), keep the default behavior. - bool usingOnlyDefaultSdk = firstSdkName == "Microsoft.NET.Sdk" && sdkDirectives.Count() <= 1; + bool usingOnlyDefaultSdk = firstSdkName == defaultSdkName && sdkDirectives.Count() <= 1; if (usingOnlyDefaultSdk) { writer.WriteLine($""" @@ -1411,9 +1412,9 @@ public static void WriteProjectFile( if (!sdkDirectives.Any()) { - Debug.Assert(firstSdkName == "Microsoft.NET.Sdk" && firstSdkVersion == null); - writer.WriteLine(""" - + Debug.Assert(firstSdkName == defaultSdkName && firstSdkVersion == null); + writer.WriteLine($""" + """); } diff --git a/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs b/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs index 72a600549d62..066d49a6ea97 100644 --- a/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs +++ b/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs @@ -394,13 +394,14 @@ public void NestedDirectory() } /// - /// Default items like None or Content are copied over. + /// Default items like None or Content are copied over if non-default SDK is used. /// [Fact] - public void DefaultItems() + public void DefaultItems_NonDefaultSdk() { var testInstance = _testAssetsManager.CreateTestDirectory(); File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ + #:sdk Microsoft.NET.Sdk.Web Console.WriteLine(); """); File.WriteAllText(Path.Join(testInstance.Path, "my.json"), ""); @@ -433,6 +434,8 @@ public void DefaultItems_MoreIncluded() var testInstance = _testAssetsManager.CreateTestDirectory(); File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ #:property EnableDefaultCompileItems=true + #:property EnableDefaultEmbeddedResourceItems=true + #:property EnableDefaultNoneItems=true Console.WriteLine(); """); File.WriteAllText(Path.Join(testInstance.Path, "my.json"), ""); @@ -487,6 +490,8 @@ public void DefaultItems_ExcludedViaMetadata() { var testInstance = _testAssetsManager.CreateTestDirectory(); File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ + #:property EnableDefaultEmbeddedResourceItems=true + #:property EnableDefaultNoneItems=true Console.WriteLine(); """); File.WriteAllText(Path.Join(testInstance.Path, "my.json"), ""); @@ -522,6 +527,7 @@ public void DefaultItems_ImplicitBuildFileInDirectory() { var testInstance = _testAssetsManager.CreateTestDirectory(); File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ + #:sdk Microsoft.NET.Sdk.Web Console.WriteLine(Util.GetText()); """); File.WriteAllText(Path.Join(testInstance.Path, "Util.cs"), """ @@ -677,6 +683,8 @@ public void DefaultItems_AlongsideProj([CombinatorialValues("sln", "slnx", "cspr var testInstance = _testAssetsManager.CreateTestDirectory(); File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """ + #:property EnableDefaultEmbeddedResourceItems=true + #:property EnableDefaultNoneItems=true Console.WriteLine(); """); File.WriteAllText(Path.Join(testInstance.Path, "my.json"), ""); diff --git a/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs b/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs index 0b0455c392df..97571bc31f1a 100644 --- a/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs +++ b/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs @@ -1372,7 +1372,7 @@ public void EmbeddedResource() File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), s_programReadingEmbeddedResource); File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx); - // By default, with the default SDK, embedded resources are not included + // By default, with the default SDK, embedded resources are not included. new DotnetCommand(Log, "run", "Program.cs") .WithWorkingDirectory(testInstance.Path) .Execute() @@ -1395,7 +1395,7 @@ Resource not found [MyString, TestValue] """); - // When using a non-default SDK, embedded resources are included by default + // When using a non-default SDK, embedded resources are included by default. File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), $""" #:sdk Microsoft.NET.Sdk.Web {s_programReadingEmbeddedResource} @@ -1408,6 +1408,20 @@ Resource not found .And.HaveStdOut(""" [MyString, TestValue] """); + + // When using the default SDK explicitly, embedded resources are not included. + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), $""" + #:sdk Microsoft.NET.Sdk + {s_programReadingEmbeddedResource} + """); + + new DotnetCommand(Log, "run", "Program.cs") + .WithWorkingDirectory(testInstance.Path) + .Execute() + .Should().Pass() + .And.HaveStdOut(""" + Resource not found + """); } /// @@ -1417,19 +1431,23 @@ Resource not found [Theory, CombinatorialData] public void EmbeddedResource_AlongsideProj([CombinatorialValues("sln", "slnx", "csproj", "vbproj", "shproj", "proj")] string ext) { + bool considered = ext is "sln" or "slnx" or "csproj"; + var testInstance = _testAssetsManager.CreateTestDirectory(); - File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), s_programReadingEmbeddedResource); + File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), $""" + #:property EnableDefaultEmbeddedResourceItems=true + {s_programReadingEmbeddedResource} + """); File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx); File.WriteAllText(Path.Join(testInstance.Path, $"repo.{ext}"), ""); // Up-to-date check currently doesn't support default items, so we need to pass --no-cache // otherwise other runs of this test theory might cause outdated results. - // With the default SDK, embedded resources are not included by default regardless of project files new DotnetCommand(Log, "run", "--no-cache", "--file", "Program.cs") .WithWorkingDirectory(testInstance.Path) .Execute() .Should().Pass() - .And.HaveStdOut("Resource not found"); + .And.HaveStdOut(considered ? "Resource not found" : "[MyString, TestValue]"); } [Fact] @@ -3186,43 +3204,12 @@ public void UpToDate_DefaultItems(bool optOut) Build(testInstance, BuildLevel.All, ["--no-cache"], expectedOutput: "[MyString, UpdatedValue]"); } - /// - /// Combination of with optimization. - /// - [Theory, CombinatorialData] // https://github.com/dotnet/sdk/issues/50912 - public void UpToDate_DefaultItems_CscOnly(bool optOut) - { - var testInstance = _testAssetsManager.CreateTestDirectory(baseDirectory: OutOfTreeBaseDirectory); - var code = $""" - {(optOut ? "#:property FileBasedProgramCanSkipMSBuild=false" : "")} - {s_programReadingEmbeddedResource} - """; - File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), code); - File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx); - - Build(testInstance, optOut ? BuildLevel.All : BuildLevel.Csc, expectedOutput: optOut ? "[MyString, TestValue]" : "Resource not found"); - - // Update the RESX file. - File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx.Replace("TestValue", "UpdatedValue")); - - Build(testInstance, optOut ? BuildLevel.All : BuildLevel.None, expectedOutput: optOut ? "[MyString, UpdatedValue]" : "Resource not found"); - - // Update the C# file. - File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), "//v2\n" + code); - - Build(testInstance, optOut ? BuildLevel.All : BuildLevel.Csc, expectedOutput: optOut ? "[MyString, UpdatedValue]" : "Resource not found"); - - Build(testInstance, BuildLevel.All, ["--no-cache"], expectedOutput: "[MyString, UpdatedValue]"); - - // Update the C# file. - File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), "//v3\n" + code); - - Build(testInstance, optOut ? BuildLevel.All : BuildLevel.Csc, expectedOutput: "[MyString, UpdatedValue]"); - } - /// /// Combination of with optimization. /// + /// + /// Note: we cannot test because that optimization doesn't support neither #:property nor #:sdk which we need to enable default items. + /// [Theory, CombinatorialData] // https://github.com/dotnet/sdk/issues/50912 public void UpToDate_DefaultItems_CscOnly_AfterMSBuild(bool optOut) { @@ -3912,6 +3899,8 @@ public void Api_Diagnostic_01() true false true + false + false Exe {ToolsetInfo.CurrentTargetFramework} enable @@ -3980,6 +3969,8 @@ public void Api_Diagnostic_02() true false true + false + false Exe {ToolsetInfo.CurrentTargetFramework} enable