question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

"dotnet publish" (Linux, MSBuild GenerateBundle task) does not include assembly metadata in PE binary for self-contained win-x64 console application

See original GitHub issue

Describe the bug

I have an Azure Pipelines release pipeline for a .NET 6 console application. My build agent is a self-hosted Ubuntu 20.04 LTS server. The pipeline is installing .NET SDK 6.0.101 before executing any other steps. I am pushing published releases to GitHub. I noticed my published application was crashing because it was attempting to read assembly metadata that appears to have been stripped from the assembly during the dotnet publish step, which is configured to perform a self-contained publish. Because I control the build agent, I was able to perform an extensive investigation to narrow down the problem.

dotnet build

Earlier in the pipeline, I perform the following dotnet build command:

/home/nathanaldensr/azure-pipelines-agent/_work/_tool/dotnet/dotnet build /home/nathanaldensr/azure-pipelines-agent/_work/2/s/Redacted.DatabaseUtilities.sln -dl:CentralLogger,"/home/nathanaldensr/azure-pipelines-agent/_work/_tasks/DotNetCoreCLI_5541a522-603c-47ad-91fc-a4b1d163081b/2.198.0/dotnet-build-helpers/Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll"*ForwardingLogger,"/home/nathanaldensr/azure-pipelines-agent/_work/_tasks/DotNetCoreCLI_5541a522-603c-47ad-91fc-a4b1d163081b/2.198.0/dotnet-build-helpers/Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll" --configuration Release --no-restore --verbosity detailed

This results in an assembly being created for the console application at ~/azure-pipelines-agent/_work/2/s/artifacts/bin/Redacted.DatabaseUtilities.PostgreSql/Release/net6.0/Redacted.DatabaseUtilities.PostgreSql.dll.

I downloaded this file to my PC and opened it in Visual Studio to inspect the PE information and also JetBrains Assembly Explorer to inspect the assembly metadata:

image

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("Redacted")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) Redacted.")]
[assembly: AssemblyFileVersion("1.0.222.8005")]
[assembly: AssemblyInformationalVersion("1.0.2+f9988f5c152416e949d1de30d643279217c1e237")]
[assembly: AssemblyProduct("Database Utilities")]
[assembly: AssemblyTitle("Redacted.DatabaseUtilities.PostgreSql")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/redacted/databaseutilities.git")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyVersion("1.0.0.0")]

As you can see, for the .NET assembly itself, everything is perfect.

dotnet publish

Here’s where the problem lies, I believe. Here is the dotnet publish command as shown by the Azure Pipelines log:

/home/nathanaldensr/azure-pipelines-agent/_work/_tool/dotnet/dotnet publish /home/nathanaldensr/azure-pipelines-agent/_work/2/s/source/PostgreSql/Redacted.DatabaseUtilities.PostgreSql.csproj --configuration Release --runtime win-x64 --self-contained true --verbosity detailed -p:PublishSingleFile=true

This results in a self-contained PE binary being created at ~/azure-pipelines-agent/_work/2/s/artifacts/bin/Redacted.DatabaseUtilities.PostgreSql/Release/net6.0/win-x64/publish/Redacted.DatabaseUtilities.PostgreSql.exe.

I downloaded this file to my PC and opened it in Visual Studio to inspect the PE information:

image

As you can see, there is no version information whatsoever. Windows Explorer confirms this:

image

Here’s the strange thing: if I run dotnet publish on my local Windows 10 PC, the executable contains the correct PE information!

PS > dotnet publish .\source\PostgreSql\Redacted.DatabaseUtilities.PostgreSql.csproj --configuration Release --runtime win-x64 --self-contained true -p:PublishSingleFile=true
Microsoft (R) Build Engine version 17.0.0+c9eb9dd64 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  Restored D:\github\redacted\databaseutilities\source\PostgreSql\Redacted.DatabaseUtilities.PostgreSql.csproj (in 331 ms).
  Redacted.DatabaseUtilities.PostgreSql -> D:\github\redacted\databaseutilities\artifacts\bin\Redacted.DatabaseUtilities.PostgreSql\Release\net6.0\win-x64\Redacted.DatabaseUtilities.PostgreSql.dll
  Redacted.DatabaseUtilities.PostgreSql -> D:\github\redacted\databaseutilities\artifacts\bin\Redacted.DatabaseUtilities.PostgreSql\Release\net6.0\win-x64\publish\

image

I ran the same CLI command through SSH, but this time I specified --verbosity diagnostic -bl:msbuild.binlog. Then I downloaded the binlog and viewed it with MSBuild Structured Log Viewer. I located the GenerateSingleFileBundle task and, inside it, the GenerateBundle task, and found this:

image

It appears that the file being included in the single file bundle is not the same file as the one output to bin by dotnet build. I downloaded the .dll selected in the screenshot and, sure enough, Windows Explorer shows the expected PE information is present. In other words, given the actual files being used by GenerateBundle, I can’t see how this isn’t a bug.

Here are some additional input parameters to the GenerateBundle task:

image

Unfortunately, further behavior of dotnet publish is opaque to me, so I’m not sure what other information I can gather. This appears to be a bug with dotnet publish in the context of Linux (hard for me to tell for sure).

I can upload the binlog somewhere as long as it’s private and secure.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:8 (1 by maintainers)

github_iconTop GitHub Comments

1reaction
KalleOlaviNiemitalocommented, Jan 31, 2022

Can you change your application to use Attribute.GetCustomAttributes, perhaps with Assembly.GetEntryAssembly? That way, the version lookup would not depend on Win32 resources.

If you instead need to publish a VERSIONINFO resource for other software to read (e.g. to let Windows Installer decide whether it should replace a file), that’s harder. Some possibilities come to mind:

  • GNU binutils might include a program capable of copying resources between PE files. I didn’t find one in the documentation, though.
  • Implement a custom utility that uses the Win32 API to copy the resources. Your CI system could still build the projects on lower-cost Linux agents but then run the resource-copying tool on Windows. Or perhaps it could even be run on Wine.
  • Implement the resource copying tool based on the PE specification without involving the Win32 API. This is what .NET should eventually do anyway but if you do it as a separate tool then you can have it sooner.
0reactions
marcpopMSFTcommented, Feb 16, 2022

Per comment above, the SDK can’t resolve this until https://github.com/dotnet/runtime/issues/3828 is fixed and we may not require any work once that’s solved.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Backlog Milestone
"dotnet publish" (Linux, MSBuild GenerateBundle task) does not include assembly metadata in PE binary for self-contained win-x64 console application Area- ...
Read more >
Using MSBuild.exe to release a net5.0 console application ...
I don't know. Now, after I try the following command : dotnet msbuild ConsoleCoreApp1.csproj /t:publish /p:Configuration=Release /p: ...
Read more >
Create a single file for application deployment - .NET
Learn what single file application is and why you should consider using this application deployment model.
Read more >
NET application publishing overview
Learn about the ways to publish a .NET application. .NET can publish platform-specific or cross-platform apps. You can publish an app as ...
Read more >
Self-Contained Single-File does not produce a single file
Net 5 console application with no dependencies on third party components. I have set it up to publish as a self-contained single-file.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found