Skip to content

dotnet format cannot format source files of .csproj (using old syntax) if Mono is installed #49208

Open
@salvadorj

Description

@salvadorj

Describe the bug

Starting with .NET SDK 8.0.409, dotnet format can no longer format source files of a .csproj with no Sdk attribute on the Project element if Mono is installed. dotnet format outputs a stack trace and the source file is not formatted:

Unhandled exception: System.Exception: The build host could not be found at '/usr/share/dotnet/sdk/8.0.409/DotnetTools/dotnet-format/BuildHost-net472/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.exe'
   at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.AssertBuildHostExists(String buildHostPath)
   at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.GetDotNetFrameworkBuildHostPath()
   at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.CreateMonoBuildHostStartInfo()
   at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.GetBuildHostAsync(BuildHostProcessKind buildHostKind, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.GetBuildHostWithFallbackAsync(BuildHostProcessKind buildHostKind, String projectOrSolutionFilePath, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.Worker.LoadProjectFileInfosAsync(String projectPath, DiagnosticReportingOptions reportingOptions, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.Worker.LoadProjectInfosFromPathAsync(String projectPath, DiagnosticReportingOptions reportingOptions, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.Worker.LoadAsync(CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.LoadProjectInfoAsync(String projectFilePath, ProjectMap projectMap, IProgress`1 progress, ILogger msbuildLogger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.LoadProjectInfoAsync(String projectFilePath, ProjectMap projectMap, IProgress`1 progress, ILogger msbuildLogger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.MSBuildWorkspace.OpenProjectAsync(String projectFilePath, ILogger msbuildLogger, IProgress`1 progress, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Tools.Workspaces.MSBuildWorkspaceLoader.LoadAsync(String solutionOrProjectPath, WorkspaceType workspaceType, String binaryLogPath, Boolean logWorkspaceWarnings, ILogger logger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Tools.CodeFormatter.OpenMSBuildWorkspaceAsync(String solutionOrProjectPath, WorkspaceType workspaceType, Boolean noRestore, Boolean requiresSemantics, String binaryLogPath, Boolean logWorkspaceWarnings, ILogger logger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Tools.CodeFormatter.FormatWorkspaceAsync(FormatOptions formatOptions, ILogger logger, CancellationToken cancellationToken, String binaryLogPath)
   at Microsoft.CodeAnalysis.Tools.FormatCommandCommon.FormatAsync(FormatOptions formatOptions, ILogger`1 logger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Tools.Commands.RootFormatCommand.FormatCommandDefaultHandler.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken)
   at System.CommandLine.Invocation.InvocationPipeline.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken)

This affects both Ubuntu (22.04) and macOS (15.5).

The issue does not reproduce with .NET SDK 8.0.408. It also does not reproduce if Mono is not installed, although an additional warning message is emitted starting with .NET SDK 8.0.409:

[Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager] An installation of Mono could not be found; /opt/work/helloworld.csproj will be loaded with the .NET Core SDK and may encounter errors.

It appears that the dotnet format command has worked with this older .csproj syntax (example) up until now, although I'm not sure if it's expected to work against a .csproj that wasn't created by dotnet new and if it's considered a bug that it no longer works. At the very least, I'd say it's a bug that it outputs a stack trace instead of an error message.

To Reproduce

  1. Create a Dockerfile file with the following contents:
ARG DOTNET_SDK_VERSION=8.0.409
FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_SDK_VERSION}-jammy-amd64

# Install Mono
ARG WITHOUT_MONO
RUN if [ -z "$WITHOUT_MONO" ]; then \
    apt-get update && \
    apt-get install -y gnupg && \
    apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF && \
    echo "deb https://download.mono-project.com/repo/ubuntu stable-focal main" > /etc/apt/sources.list.d/mono-official-stable.list && \
    apt-get update && \
    apt-get install -y mono-complete ; \
    fi

# Run dotnet format (with a minimal MSBuild project file)
# https://learn.microsoft.com/en-us/visualstudio/msbuild/walkthrough-creating-an-msbuild-project-file-from-scratch?view=vs-2022#create-a-minimal-msbuild-project-file
WORKDIR /opt/work
RUN cat > helloworld.csproj <<EOF
<Project>
  <ItemGroup>
    <Compile Include="helloworld.cs"/>
  </ItemGroup>
  <Target Name="Build">
    <Csc Sources="@(Compile)"/>
  </Target>
</Project>
EOF
RUN cat > helloworld.cs <<EOF
using System;

class HelloWorld
{
    static void Main()
    {
Console.WriteLine("Hello, world!"); // bad indentation
    }
}
EOF
RUN bash <<EOF
set -x
dotnet --info
dotnet format helloworld.csproj -v diag
echo "dotnet exit status: \$?"
cat helloworld.cs
false
EOF
  1. Run docker build . --platform linux/amd64.
  2. Observe that dotnet format did not format helloworld.cs and output an unhandled exception:
...
0.128 + dotnet --info
0.603 .NET SDK:
0.604  Version:           8.0.409
0.604  Commit:            5f0de3de48
0.741  Workload version:  8.0.400-manifests.def3829e
0.742  MSBuild version:   17.11.31+933b72e36
0.742
0.742 Runtime Environment:
0.746  OS Name:     ubuntu
0.746  OS Version:  22.04
0.749  OS Platform: Linux
0.763  RID:         linux-x64
0.763  Base Path:   /usr/share/dotnet/sdk/8.0.409/
0.763
0.763 .NET workloads installed:
0.768 Configured to use loose manifests when installing new manifests.
0.768 There are no installed workloads to display.
0.775
0.775 Host:
0.775   Version:      8.0.16
0.775   Architecture: x64
0.775   Commit:       efd5742bb5
0.775
0.775 .NET SDKs installed:
0.775   8.0.409 [/usr/share/dotnet/sdk]
0.775
0.775 .NET runtimes installed:
0.775   Microsoft.AspNetCore.App 8.0.16 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
0.775   Microsoft.NETCore.App 8.0.16 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
0.775
0.775 Other architectures found:
0.775   None
0.775
0.775 Environment variables:
0.775   Not set
0.775
0.775 global.json file:
0.775   Not found
0.775
0.775 Learn more:
0.775   https://aka.ms/dotnet/info
0.775
0.775 Download .NET:
0.775   https://aka.ms/dotnet/download
0.779 + dotnet format helloworld.csproj -v diag
2.105   The dotnet runtime version is '8.0.16'.
2.645   The dotnet CLI version is '8.0.409'.
2.716   Using MSBuild.exe located in '/usr/share/dotnet/sdk/8.0.409/'.
2.722   Formatting code files in workspace '/opt/work/helloworld.csproj'.
2.722   Loading workspace.
3.799
4.739 Unhandled exception: System.Exception: The build host could not be found at '/usr/share/dotnet/sdk/8.0.409/DotnetTools/dotnet-format/BuildHost-net472/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.exe'
4.755    at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.AssertBuildHostExists(String buildHostPath)
4.755    at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.GetDotNetFrameworkBuildHostPath()
4.755    at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.CreateMonoBuildHostStartInfo()
4.755    at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.GetBuildHostAsync(BuildHostProcessKind buildHostKind, CancellationToken cancellationToken)
4.755    at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.GetBuildHostWithFallbackAsync(BuildHostProcessKind buildHostKind, String projectOrSolutionFilePath, CancellationToken cancellationToken)
4.755    at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.Worker.LoadProjectFileInfosAsync(String projectPath, DiagnosticReportingOptions reportingOptions, CancellationToken cancellationToken)
4.755    at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.Worker.LoadProjectInfosFromPathAsync(String projectPath, DiagnosticReportingOptions reportingOptions, CancellationToken cancellationToken)
4.755    at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.Worker.LoadAsync(CancellationToken cancellationToken)
4.755    at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.LoadProjectInfoAsync(String projectFilePath, ProjectMap projectMap, IProgress`1 progress, ILogger msbuildLogger, CancellationToken cancellationToken)
4.755    at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.LoadProjectInfoAsync(String projectFilePath, ProjectMap projectMap, IProgress`1 progress, ILogger msbuildLogger, CancellationToken cancellationToken)
4.755    at Microsoft.CodeAnalysis.MSBuild.MSBuildWorkspace.OpenProjectAsync(String projectFilePath, ILogger msbuildLogger, IProgress`1 progress, CancellationToken cancellationToken)
4.755    at Microsoft.CodeAnalysis.Tools.Workspaces.MSBuildWorkspaceLoader.LoadAsync(String solutionOrProjectPath, WorkspaceType workspaceType, String binaryLogPath, Boolean logWorkspaceWarnings, ILogger logger, CancellationToken cancellationToken)
4.755    at Microsoft.CodeAnalysis.Tools.CodeFormatter.OpenMSBuildWorkspaceAsync(String solutionOrProjectPath, WorkspaceType workspaceType, Boolean noRestore, Boolean requiresSemantics, String binaryLogPath, Boolean logWorkspaceWarnings, ILogger logger, CancellationToken cancellationToken)
4.755    at Microsoft.CodeAnalysis.Tools.CodeFormatter.FormatWorkspaceAsync(FormatOptions formatOptions, ILogger logger, CancellationToken cancellationToken, String binaryLogPath)
4.755    at Microsoft.CodeAnalysis.Tools.FormatCommandCommon.FormatAsync(FormatOptions formatOptions, ILogger`1 logger, CancellationToken cancellationToken)
4.755    at Microsoft.CodeAnalysis.Tools.Commands.RootFormatCommand.FormatCommandDefaultHandler.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken)
4.755    at System.CommandLine.Invocation.InvocationPipeline.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken)
4.808 + echo 'dotnet exit status: 1'
4.808 dotnet exit status: 1
4.808 + cat helloworld.cs
4.820 using System;
4.820
4.820 class HelloWorld
4.820 {
4.820     static void Main()
4.820     {
4.820 Console.WriteLine("Hello, world!"); // bad indentation
4.820     }
4.820 }
...

Run docker build . --platform linux/amd64 --build-arg WITHOUT_MONO=1 to run the test again without Mono installed and observe that dotnet format does format helloworld.cs (even if it outputs a warning message):

...
0.781 + dotnet format helloworld.csproj -v diag
...
2.798   Formatting code files in workspace '/opt/work/helloworld.csproj'.
2.798   Loading workspace.
3.925
6.150 [Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager] An installation of Mono could not be found; /opt/work/helloworld.csproj will be loaded with the .NET Core SDK and may encounter errors.
6.150 Msbuild failed when processing the file '/opt/work/helloworld.csproj' with message: Project does not contain 'Compile' target.
6.153   Complete in 3353ms.
6.153   Determining formattable files.
6.345   Complete in 193ms.
6.345   Running formatters.
...
8.114   Formatted code file '/opt/work/helloworld.cs'.
8.191   Formatted 1 of 1 files.
8.191   Format complete in 5392ms.
8.259 + echo 'dotnet exit status: 0'
8.259 dotnet exit status: 0
8.260 + cat helloworld.cs
8.271 using System;
8.271
8.271 class HelloWorld
8.271 {
8.271     static void Main()
8.271     {
8.271         Console.WriteLine("Hello, world!"); // bad indentation
8.271     }
8.271 }
...

Run docker build . --platform linux/amd64 --build-arg DOTNET_SDK_VERSION=8.0.408 to run the test again with .NET SDK 8.0.408 (and Mono installed) and observe that dotnet format does format helloworld.cs:

...
0.116 + dotnet --info
0.593 .NET SDK:
0.593  Version:           8.0.408
0.593  Commit:            e6663e9b3d
0.729  Workload version:  8.0.400-manifests.22ac4dbc
0.730  MSBuild version:   17.11.26+2b19be476
...
0.767 + dotnet format helloworld.csproj -v diag
2.077   The dotnet runtime version is '8.0.15'.
2.607   The dotnet CLI version is '8.0.408'.
2.683   Using MSBuild.exe located in '/usr/share/dotnet/sdk/8.0.408/'.
2.689   Formatting code files in workspace '/opt/work/helloworld.csproj'.
2.689   Loading workspace.
3.760
4.941 Msbuild failed when processing the file '/opt/work/helloworld.csproj' with message: Project does not contain 'Compile' target.
4.945   Complete in 2254ms.
4.945   Determining formattable files.
5.132   Complete in 188ms.
5.132   Running formatters.
...
6.691   Formatted code file '/opt/work/helloworld.cs'.
6.726   Formatted 1 of 1 files.
6.726   Format complete in 4036ms.
6.790 + echo 'dotnet exit status: 0'
6.790 + cat helloworld.cs
6.790 dotnet exit status: 0
6.802 using System;
6.802
6.802 class HelloWorld
6.802 {
6.802     static void Main()
6.802     {
6.802         Console.WriteLine("Hello, world!"); // bad indentation
6.802     }
6.802 }
...

Exceptions (if any)

Unhandled exception: System.Exception: The build host could not be found at '/usr/share/dotnet/sdk/8.0.409/DotnetTools/dotnet-format/BuildHost-net472/Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.exe'
   at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.AssertBuildHostExists(String buildHostPath)
   at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.GetDotNetFrameworkBuildHostPath()
   at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.CreateMonoBuildHostStartInfo()
   at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.GetBuildHostAsync(BuildHostProcessKind buildHostKind, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.BuildHostProcessManager.GetBuildHostWithFallbackAsync(BuildHostProcessKind buildHostKind, String projectOrSolutionFilePath, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.Worker.LoadProjectFileInfosAsync(String projectPath, DiagnosticReportingOptions reportingOptions, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.Worker.LoadProjectInfosFromPathAsync(String projectPath, DiagnosticReportingOptions reportingOptions, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.Worker.LoadAsync(CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.LoadProjectInfoAsync(String projectFilePath, ProjectMap projectMap, IProgress`1 progress, ILogger msbuildLogger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.MSBuildProjectLoader.LoadProjectInfoAsync(String projectFilePath, ProjectMap projectMap, IProgress`1 progress, ILogger msbuildLogger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.MSBuild.MSBuildWorkspace.OpenProjectAsync(String projectFilePath, ILogger msbuildLogger, IProgress`1 progress, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Tools.Workspaces.MSBuildWorkspaceLoader.LoadAsync(String solutionOrProjectPath, WorkspaceType workspaceType, String binaryLogPath, Boolean logWorkspaceWarnings, ILogger logger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Tools.CodeFormatter.OpenMSBuildWorkspaceAsync(String solutionOrProjectPath, WorkspaceType workspaceType, Boolean noRestore, Boolean requiresSemantics, String binaryLogPath, Boolean logWorkspaceWarnings, ILogger logger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Tools.CodeFormatter.FormatWorkspaceAsync(FormatOptions formatOptions, ILogger logger, CancellationToken cancellationToken, String binaryLogPath)
   at Microsoft.CodeAnalysis.Tools.FormatCommandCommon.FormatAsync(FormatOptions formatOptions, ILogger`1 logger, CancellationToken cancellationToken)
   at Microsoft.CodeAnalysis.Tools.Commands.RootFormatCommand.FormatCommandDefaultHandler.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken)
   at System.CommandLine.Invocation.InvocationPipeline.InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken)

Further technical details

  • Include the output of dotnet --info
.NET SDK:
 Version:           8.0.409
 Commit:            5f0de3de48
 Workload version:  8.0.400-manifests.def3829e
 MSBuild version:   17.11.31+933b72e36

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  22.04
 OS Platform: Linux
 RID:         linux-x64
 Base Path:   /usr/share/dotnet/sdk/8.0.409/

.NET workloads installed:
Configured to use loose manifests when installing new manifests.
There are no installed workloads to display.

Host:
  Version:      8.0.16
  Architecture: x64
  Commit:       efd5742bb5

.NET SDKs installed:
  8.0.409 [/usr/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 8.0.16 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 8.0.16 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download
  • The IDE (VS / VS Code/ VS4Mac) you're running on, and its version

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions