"dotnet publish" (Linux, MSBuild GenerateBundle task) does not include assembly metadata in PE binary for self-contained win-x64 console application
See original GitHub issueDescribe 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:
[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:
As you can see, there is no version information whatsoever. Windows Explorer confirms this:
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\
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:
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:
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:
- Created 2 years ago
- Comments:8 (1 by maintainers)
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:
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.