Skip to content

Conversation

@jjonescz
Copy link
Member

Resolves #49826.

@jjonescz jjonescz added the Area-run-file Items related to the "dotnet run <file>" effort label Jul 30, 2025
Comment on lines 20 to 22
('$([System.IO.Directory]::GetFiles($(MSBuildProjectDirectory), &quot;*.sln&quot;))' != '' Or
$([System.IO.Directory]::GetFiles($(MSBuildProjectDirectory), &quot;*.slnx&quot;)) != '' Or
$([System.IO.Directory]::GetFiles($(MSBuildProjectDirectory), &quot;*.*proj&quot;)) != '')">false</EnableDefaultItems>
Copy link
Member

Choose a reason for hiding this comment

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

These calls return arrays, so checking Length != 0 might be more clear here, and wouldn't require MSBuild to coerce the return to a string for checking.

@rainersigwald one thing I think about with IO-based property functions - do these go through MSBuild's IO abstractions, or are they direct BCL calls? Are there things we need to worry about in general with the IO calls in MSBuild logic with multithreaded MSBuild (I know we want to prevent the use of some of these calls in Tasks)?

Copy link
Member

Choose a reason for hiding this comment

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

I know we have code to not force an item expansion to stringify when compared to empty string, but I don't know if it works in this property-function case.

I think today we do straight passthrough to BCL but I wouldn't want to stop us from doing something better in the future.

But evaluation is already parallel in many cases and calling this should be fine (as long as you don't like depend on mutating filesystem state between projects).

@jjonescz jjonescz marked this pull request as ready for review July 30, 2025 16:48
@jjonescz jjonescz requested review from a team and Copilot July 30, 2025 16:48
Copy link
Contributor

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

This PR resolves an issue where file-based apps would incorrectly include default items (like .resx files and .cs files) when running in directories that contain project or solution files. The fix introduces a new property DisableDefaultItemsInProjectFolder that automatically disables default items when project/solution files are detected in the same directory.

Key changes:

  • Adds logic to automatically disable default items in project folders for file-based apps
  • Updates test coverage to verify the new behavior with embedded resources and default items
  • Refactors existing test code to use shared constants for better maintainability

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.targets Implements the core logic to disable default items when project/solution files are detected
src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs Sets the DisableDefaultItemsInProjectFolder property for file-based programs
test/dotnet.Tests/CommandTests/Run/RunFileTests.cs Adds test coverage and refactors existing tests to use shared constants
test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs Adds test coverage for the conversion scenario
documentation/general/dotnet-run-file.md Updates documentation to describe the new behavior

'$(DisableDefaultItemsInProjectFolder)' == 'true' And
('$([System.IO.Directory]::GetFiles($(MSBuildProjectDirectory), &quot;*.sln&quot;).Length)' != '0' Or
'$([System.IO.Directory]::GetFiles($(MSBuildProjectDirectory), &quot;*.slnx&quot;).Length)' != '0' Or
'$([System.IO.Directory]::GetFiles($(MSBuildProjectDirectory), &quot;*.*proj&quot;).Length)' != '0')">false</EnableDefaultItems>
Copy link
Member

Choose a reason for hiding this comment

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

I would feel more comfortable with identifying the exact set of extensions we want to condition the behavior on. For example, xcode projects use extension .pbxproj. I wouldn't expect us to change our behavior based on the presence of 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.

Note that this is based on the existing logic here:

<DefaultItemExcludes>$(DefaultItemExcludes);**/*.*proj</DefaultItemExcludes>

But I guess that's different.

For example, xcode projects use extension .pbxproj. I wouldn't expect us to change our behavior based on the presence of it.

I'm not sure why not, file-based apps shouldn't be in project folders anyway.

Copy link
Member

Choose a reason for hiding this comment

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

I guess I am saying that if there is some proj file present, whose exact extension we don't actually know, we just don't know what it means. If there were some multimedia software, where the project format ends with proj, which the user had some reason for including in a folder with a FBP, it doesn't feel reasonable for us to condition our behavior based on that, for the same reason as the xcode case.

Like, basically imagine the bug report where someone says I tried putting my "completely unrelated to dotnet/msbuild" file into this folder and now my FBP won't build. How were they supposed to reason that this is something that would/should happen?

Copy link
Member Author

Choose a reason for hiding this comment

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

Makes sense, I can change to specific extensions, thanks. But still, handling the whole *proj pattern is common in .net sdk anyway, see https://github.com/search?q=repo%3Adotnet%2Fsdk%20%22*.*proj%22&type=code

Copy link
Member

Choose a reason for hiding this comment

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

It's good to know that we don't protect against this possibility in general. For example it might be the case today that having a random unrelated *proj file, breaks dotnet build . in that folder. In which case I'm ok with you deciding to defend against this case or not at your discretion.


- `DisableDefaultItemsInProjectFolder` property is set to `true` which results in `EnableDefaultItems=false` by default
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.
Copy link
Member

Choose a reason for hiding this comment

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

I think I'm confused by the need to probe for project/solutions. In this new mode how does the c# file get included in the project if not via default glob? If it's explicitly included, why is the probing needed?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, the .cs file is included explicitly (that might change in .net 11 with multi-file mode though). The globbing is still used for other default items like .resx (EmbeddedResource) or .json (Content in web apps).

@jaredpar
Copy link
Member

jaredpar commented Aug 4, 2025

@JoeRobich, @RikkiGibson PTAL

var testInstance = _testAssetsManager.CreateTestDirectory();
File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), s_programReadingEmbeddedResource);
File.WriteAllText(Path.Join(testInstance.Path, "Resources.resx"), s_resx);
File.WriteAllText(Path.Join(testInstance.Path, "repo.sln"), "");
Copy link
Member

Choose a reason for hiding this comment

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

Consider also including cases for the other file types .csproj .slnx we have this behavior for, as well as a file type where we don't exclude default items but may consider doing so in future, such as .shproj.

Copy link
Member

@RikkiGibson RikkiGibson left a comment

Choose a reason for hiding this comment

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

LGTM, just one minor suggestion, non-blocking

@jjonescz
Copy link
Member Author

@MiYanni for a review, thanks

@jjonescz jjonescz merged commit c2d964b into dotnet:main Aug 13, 2025
27 checks passed
@jjonescz jjonescz deleted the sprint-sln branch August 13, 2025 07:47
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dotnet run file.cs should not pick up implicit build files by default

7 participants