.NET8/9 – Testing Different Build/Deployment Modes – Part 6

Abstract: We practically show examples of 15 different .NET8/9 build modes, including Framework-Dependent and Framework-Independent, how to bundle an app into a single file, how to trim app bundles from unused libraries, and how to build an Ahead-of-time (AOT) precompiled app.

1. .NET8/9 toolset supports different build/publish/deployment modes

I was experimenting with different project properties/flags, and I developed several proof-of-concept build projects showcasing different build/publish/deployment modes available in .NET8/9, using Microsoft tools.

1.2. Articles in this series

For technical reasons, I will organize this text into several articles.

  • .NET8/9 – Testing different Build/Deployment modes – Part 1
  • .NET8/9 – Testing different Build/Deployment modes – Part 2
  • .NET8/9 – Testing different Build/Deployment modes – Part 3
  • .NET8/9 – Testing different Build/Deployment modes – Part 4
  • .NET8/9 – Testing different Build/Deployment modes – Part 5
  • .NET8/9 – Testing different Build/Deployment modes – Part 6

2. New build configurations for NET 8.0.11 and NET 9.0.0

New build configurations/scripts for NET_8.0.11/SDK_8.0.404 and NET_9.0.0/SDK_9.0.101 environments are here. Build types and the rationale are as before, just some new build tricks were made. Any better C# developer should be able to understand these build settings.

These are builds in NET_8.0.11/SDK_8.0.404 environment.
All these builds worked also in NET_9.0.0/SDK_9.0.101 environment. 
===Build 1=======================================================================
Location: 
->\ConsoleApp1\bin\Release\net8.0-windows\win-x64\

Publish mode:
1)Release; 2)framework-dependent; 3)Platform-specific-win-x64; 4)Un-bundled; 5)Untrimmed; 6)NotR2R; 7)PdbEmbeded; 8)binariesNotInSingleFile; 9)assembliesNotCompressed; 10)NotAot   

Works! App started and it runs properly.

Content:
-47 files
-13.3 MB

-----Here is project file---------------
<!--ConsoleApp1.csproj +++++++++++++++++++++++++++++++++++++-->
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0-windows</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <PlatformTarget>x64</PlatformTarget>
        <Platforms>AnyCPU;x64</Platforms>
        <RuntimeIdentifier>win-x64</RuntimeIdentifier>
        <DebugType>embedded</DebugType>
        <PublishSingleFile>true</PublishSingleFile>
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\ClassLibrary1\ClassLibraryA.csproj" />
    </ItemGroup>

    <Target Name="RunAfterBuild1" AfterTargets="Build">
        <Exec Command="call Framework_SingleFile_Win-X64.cmd" Condition=" '$(BuildingInsideVisualStudio)' == 'true' "/>
    </Target>

</Project>

===Build 2=======================================================================
Location: 
->\ConsoleApp1\Framework_SingleFile_Win-X64\

Publish mode:
1)Release; 2)framework-dependent; 3)Platform-specific-win-x64; 4)Single-file; 5)Untrimmed; 6)NotR2R; 7)PdbEmbeded; 8)binariesNotInSingleFile; 9)assembliesNotCompressed; 10)NotAot   

Works! App started and it runs properly.

Content:
-2 files
-13.3 MB

----Use previous project file and this script-------------------
Framework_SingleFile_Win-X64.cmd
echo .NET SDK version:
dotnet --version
dotnet publish ConsoleApp1.csproj --nologo --no-restore --runtime win-x64 --use-current-runtime  --configuration Release   -p:PublishSingleFile=true --no-self-contained --output ./Framework_SingleFile_Win-X64 

===Build 3-Build that I was not able to make==================================================
Location:
->\ConsoleApp4\Framework_SingleFile_Win-X64_Trimmed\

Publish mode:
1)Release; 2)framework-dependent; 3)Platform-specific-win-x64; 4)Single-file; 5)Trimmed; 6)Not-precompiled; 7)PdbEmbeded; 8)binariesNotInSingleFile; 9)assembliesNotCompressed  

I was looking into options, but was not able to make "Framework-dependent_Single-file_Trimmed" build.
It looks like Trimmed builds are possible with Microsoft tools in .NET8 only for self-contained (which is opposite to framework-dependent) mode builds.
I was getting this when tried:
Error (active)    NETSDK1102    Optimizing assemblies for size is not supported for the selected publish configuration. Please ensure that you are publishing a self-contained app. 

-----Here is project file---------------
<!--ConsoleApp1.csproj +++++++++++++++++++++++++++++++++++++-->
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0-windows</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <PlatformTarget>x64</PlatformTarget>
        <Platforms>AnyCPU;x64</Platforms>
        <RuntimeIdentifier>win-x64</RuntimeIdentifier>
        <DebugType>embedded</DebugType>
        <PublishTrimmed>true</PublishTrimmed>
        <IsTrimmable>true</IsTrimmable>
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\ClassLibrary1\ClassLibraryA.csproj" />
    </ItemGroup>

    <Target Name="RunAfterBuild1" AfterTargets="Build">
        <Exec Command="Framework_SingleFile_Win-X64_Trimmed.cmd" Condition=" '$(BuildingInsideVisualStudio)' == 'true' "/>
    </Target>

</Project>

----Use previous project file and this script-------------------
Framework_SingleFile_Win-X64_Trimmed.cmd
echo .NET SDK version:
dotnet --version
dotnet publish ConsoleApp4.csproj --nologo --no-restore --runtime win-x64 --use-current-runtime  --configuration Release   -p:PublishSingleFile=true --no-self-contained -p:PublishTrimmed=true --output ./Framework_SingleFile_Win-X64_Trimmed

===Build 4=======================================================================
Location: 
->\ConsoleApp2\bin\Release\net8.0-windows\win-x64\

Publish mode:
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Un-bundled; 5)Untrimmed; 6)NotR2R; 7)PdbEmbeded; 8)binariesNotInSingleFile; 9)assembliesNotCompressed ; 10)NotAot  

Works! App started and it runs properly.

Content:
-255 files
-90 MB

-----Here is project file---------------
<!--ConsoleApp2.csproj +++++++++++++++++++++++++++++++++++++-->
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0-windows</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <PlatformTarget>x64</PlatformTarget>
        <Platforms>AnyCPU;x64</Platforms>
        <RuntimeIdentifier>win-x64</RuntimeIdentifier>
        <DebugType>embedded</DebugType>
        <PublishSingleFile>true</PublishSingleFile>
        <PublishTrimmed>true</PublishTrimmed>
        <IsTrimmable>true</IsTrimmable>
        <SelfContained>true</SelfContained>
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\ClassLibrary1\ClassLibraryA.csproj" />
    </ItemGroup>

    <Target Name="RunAfterBuild1" AfterTargets="Build">
        <Exec Command="call SelfContained_SingleFile_win-x64.cmd" Condition=" '$(BuildingInsideVisualStudio)' == 'true' "/>
    </Target>

    <Target Name="RunAfterBuild2" AfterTargets="Build">
        <Exec Command="call SelfContained_SingleFile_win-x64_Trimmed.cmd" Condition=" '$(BuildingInsideVisualStudio)' == 'true' "/>
    </Target>

</Project>

===Build 5=======================================================================
Location: 
->\ConsoleApp2\SelfContained_SingleFile_win-x64\

Publish mode:
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Single-file; 5)Untrimmed; 6)NotR2R; 7)PdbEmbeded; 8)binariesNotInSingleFile; 9)assembliesNotCompressed ; 10)NotAot  

Works! App started and it runs properly.

Content:
-2 files
-75 MB

----Use previous project file and this script-------------------
SelfContained_SingleFile_win-x64.cmd
echo .NET SDK version:
dotnet --version
dotnet publish ConsoleApp2.csproj --nologo --no-restore --runtime win-x64 --configuration Release   -p:PublishSingleFile=true -p:SelfContained=true -p:PublishReadyToRun=false  -p:PublishTrimmed=false --output ./SelfContained_SingleFile_win-x64

===Build 6=======================================================================
Location: 
->\ConsoleApp2\SelfContained_SingleFile_win-x64_Trimmed\

Publish mode:
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Single-file; 5)Trimmed; 6)NotR2R; 7)PdbEmbeded; 8)binariesNotInSingleFile; 9)assembliesNotCompressed ; 10)NotAot  

Works! App started and it runs properly.

Content:
-2 files
-12 MB

----Use previous project file and this script-------------------
SelfContained_SingleFile_win-x64_Trimmed.cmd
echo .NET SDK version:
dotnet --version
dotnet publish ConsoleApp2.csproj --nologo --no-restore --runtime win-x64 --configuration Release   -p:PublishSingleFile=true -p:SelfContained=true -p:PublishReadyToRun=false  -p:PublishTrimmed=true --output ./SelfContained_SingleFile_win-x64_Trimmed

===Build 7=======================================================================
Location: 
->\ConsoleApp3\bin\Release\net8.0-windows\win-x64\

Publish mode :
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Un-bundled; 5)Untrimmed; 6)Not-precompiled; 7)PdbEmbeded; 8)binariesNotInSingleFile; 9)assembliesNotCompressed ; 10)NotAot  
(I think above is correct interpretation. I am not sure because there are many flags/properties in
the project file, but it seems they do not have effect until "dotnet publish" is called)

Works! App started and it runs properly.

Content:
-255 files
-90 MB

-----Here is project file---------------
<!--ConsoleApp3.csproj +++++++++++++++++++++++++++++++++++++-->
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0-windows</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <PlatformTarget>x64</PlatformTarget>
        <Platforms>AnyCPU;x64</Platforms>
        <RuntimeIdentifier>win-x64</RuntimeIdentifier>
        <DebugType>embedded</DebugType>
        <PublishSingleFile>true</PublishSingleFile>
        <PublishTrimmed>true</PublishTrimmed>
        <IsTrimmable>true</IsTrimmable>
        <SelfContained>true</SelfContained>
        <PublishReadyToRun>true</PublishReadyToRun>
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\ClassLibrary1\ClassLibraryA.csproj" />
    </ItemGroup>

    <Target Name="RunAfterBuild1" AfterTargets="Build">
        <Exec Command="call SelfContained_SingleFile_win-x64_ReadyToRun.cmd" Condition=" '$(BuildingInsideVisualStudio)' == 'true' "/>
    </Target>

    <Target Name="RunAfterBuild2" AfterTargets="Build">
        <Exec Command="call SelfContained_SingleFile_win-x64_Trimmed_ReadyToRun.cmd" Condition=" '$(BuildingInsideVisualStudio)' == 'true' "/>
    </Target>

</Project>

===Build 8=======================================================================
Location: 
->\ConsoleApp3\SelfContained_SingleFile_win-x64_ReadyToRun\

Publish mode :
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Single-file; 5)Untrimmed; 6)ReadyToRun; 7)PdbEmbeded; 8)binariesNotInSingleFile; 9)assembliesNotCompressed ; 10)NotAot  

Works! App started and it runs properly.

Content:
-2 files
-108 MB

----Use previous project file and this script-------------------
SelfContained_SingleFile_win-x64_ReadyToRun.cmd
echo .NET SDK version:
dotnet --version
dotnet publish ConsoleApp3.csproj --nologo --no-restore --runtime win-x64 --configuration Release   -p:PublishSingleFile=true -p:SelfContained=true -p:PublishTrimmed=false -p:PublishReadyToRun=true   --output ./SelfContained_SingleFile_win-x64_ReadyToRun

===Build 9=======================================================================
Location: 
->\ConsoleApp3\SelfContained_SingleFile_win-x64_Trimmed_ReadyToRun\

Publish mode :
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Single-file; 5)Trimmed; 6)ReadyToRun; 7)PdbEmbeded; 8)binariesNotInSingleFile; 9)assembliesNotCompressed ; 10)NotAot  

Works! App started and it runs properly.

Content:
-2 files
-15 MB

----Use previous project file and this script-------------------
SelfContained_SingleFile_win-x64_Trimmed_ReadyToRun.cmd
echo .NET SDK version:
dotnet --version
dotnet publish ConsoleApp3.csproj --nologo --no-restore --runtime win-x64 --configuration Release   -p:PublishSingleFile=true -p:SelfContained=true -p:PublishReadyToRun=true  -p:PublishTrimmed=true --output ./SelfContained_SingleFile_win-x64_Trimmed_ReadyToRun

===Build 10=======================================================================
Location: 
->\ConsoleApp1C\bin\Release\net8.0-windows\win-x64\

Publish mode:
1)Release; 2)framework-dependent; 3)Platform-specific-win-x64; 4)Un-bundled; 5)Untrimmed; 6)NotR2R; 7)PdbEmbeded; 8)binariesNotInSingleFile ; 9)assembliesNotCompressed ; 10)NotAot  

Works! App started and it runs properly.

Content:
-47 files
-13 MB
(flags do not work on this level of build)

-----Here is project file---------------
<!--ConsoleApp1C.csproj +++++++++++++++++++++++++++++++++++++-->
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0-windows</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <PlatformTarget>x64</PlatformTarget>
        <Platforms>AnyCPU;x64</Platforms>
        <RuntimeIdentifier>win-x64</RuntimeIdentifier>
        <DebugType>embedded</DebugType>
        <PublishSingleFile>true</PublishSingleFile>
        <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>    
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\ClassLibrary1\ClassLibraryA.csproj" />
    </ItemGroup>

    <Target Name="RunAfterBuild1" AfterTargets="Build">
        <Exec Command="Framework_SingleFile_Win-X64.cmd" Condition=" '$(BuildingInsideVisualStudio)' == 'true' "/>
    </Target>

</Project>

===Build 11=======================================================================
Location: 
->\ConsoleApp1C\Framework_SingleFile_Win-X64\

Publish mode:
1)Release; 2)framework-dependent; 3)Platform-specific-win-x64; 4)Single-file; 5)Untrimmed; 6)NotR2R; 7)PdbEmbeded; 8)binariesInSingleFile ; 9)assembliesNotCompressed ; 10)NotAot  

Works! App started and it runs properly.

Content:
-1 file
-14 MB

----Use previous project file and this script-------------------
Framework_SingleFile_Win-X64.cmd
echo .NET SDK version:
dotnet --version
dotnet publish ConsoleApp1C.csproj --nologo --no-restore --runtime win-x64 --use-current-runtime  --configuration Release   -p:PublishSingleFile=true --no-self-contained --output ./Framework_SingleFile_Win-X64 

===Build 12=======================================================================
Location: 
->\ConsoleApp2C\bin\Release\net8.0-windows\win-x64\

Publish mode:
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Un-bundled; 5)Untrimmed; 6)NotR2R; 7)PdbEmbeded; 8)binariesInSingleFile; 9)assembliesCompressed ; 10)NotAot   

Works! App started and it runs properly.

Content:
-255 files
-90 MB

-----Here is project file---------------
<!--ConsoleApp2C.csproj +++++++++++++++++++++++++++++++++++++-->
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0-windows</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <PlatformTarget>x64</PlatformTarget>
        <Platforms>AnyCPU;x64</Platforms>
        <RuntimeIdentifier>win-x64</RuntimeIdentifier>
        <DebugType>embedded</DebugType>
        <PublishSingleFile>true</PublishSingleFile>
        <PublishTrimmed>true</PublishTrimmed>
        <IsTrimmable>true</IsTrimmable>
        <SelfContained>true</SelfContained>
        <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
        <EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\ClassLibrary1\ClassLibraryA.csproj" />
    </ItemGroup>

    <Target Name="RunAfterBuild1" AfterTargets="Build">
        <Exec Command="call SelfContained_SingleFile_win-x64.cmd" Condition=" '$(BuildingInsideVisualStudio)' == 'true' "/>
    </Target>

    <Target Name="RunAfterBuild2" AfterTargets="Build">
        <Exec Command="call SelfContained_SingleFile_win-x64_Trimmed.cmd" Condition=" '$(BuildingInsideVisualStudio)' == 'true' "/>
    </Target>

</Project>

===Build 13=======================================================================
Location: 
->\ConsoleApp2C\SelfContained_SingleFile_win-x64\

Publish mode:
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Single-file; 5)Untrimmed; 6)NotR2R; 7)PdbEmbeded; 8)binariesInSingleFile; 9)assembliesCompressed; 10)NotAot   

Works! App started and it runs properly.

Content:
-1 file
-39 MB

----Use previous project file and this script-------------------
SelfContained_SingleFile_win-x64.cmd
echo .NET SDK version:
dotnet --version
dotnet publish ConsoleApp2C.csproj --nologo --no-restore --runtime win-x64 --configuration Release   -p:PublishSingleFile=true -p:SelfContained=true -p:PublishReadyToRun=false  -p:PublishTrimmed=false --output ./SelfContained_SingleFile_win-x64

===Build 14=======================================================================
Location: 
->\ConsoleApp2C\SelfContained_SingleFile_win-x64_Trimmed\

Publish mode:
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Single-file; 5)Trimmed; 6)NotR2R; 7)PdbEmbeded; 8)binariesInSingleFile; 9)assembliesCompressed ; 10)NotAot    

Works! App started and it runs properly.

Content:
-1 file
-10 MB

----Use previous project file and this script-------------------
SelfContained_SingleFile_win-x64_Trimmed.cmd
echo .NET SDK version:
dotnet --version
dotnet publish ConsoleApp2C.csproj --nologo --no-restore --runtime win-x64 --configuration Release   -p:PublishSingleFile=true -p:SelfContained=true -p:PublishReadyToRun=false  -p:PublishTrimmed=true --output ./SelfContained_SingleFile_win-x64_Trimmed


===Build 15=======================================================================
Location: 
->\ConsoleApp3C\bin\Release\net8.0-windows\win-x64\

Publish mode :
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Un-bundled; 5)Untrimmed; 6)NotR2R; 7)PdbEmbeded; 8)binariesNotInSingleFile; 9)assembliesNotCompressed ; 10)NotAot  
(I think above is correct interpretation. I am not sure because there are many flags/properties in
the project file, but it seems they do not have effect until "dotnet publish" is called)

Works! App started and it runs properly.

Content:
-255 files
-90 MB

-----Here is project file---------------
<!--ConsoleApp3C.csproj +++++++++++++++++++++++++++++++++++++-->
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0-windows</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <PlatformTarget>x64</PlatformTarget>
        <Platforms>AnyCPU;x64</Platforms>
        <RuntimeIdentifier>win-x64</RuntimeIdentifier>
        <DebugType>embedded</DebugType>
        <PublishSingleFile>true</PublishSingleFile>
        <PublishTrimmed>true</PublishTrimmed>
        <IsTrimmable>true</IsTrimmable>
        <SelfContained>true</SelfContained>
        <PublishReadyToRun>true</PublishReadyToRun>
        <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
        <EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\ClassLibrary1\ClassLibraryA.csproj" />
    </ItemGroup>

    <Target Name="RunAfterBuild1" AfterTargets="Build">
        <Exec Command="call SelfContained_SingleFile_win-x64_ReadyToRun.cmd" Condition=" '$(BuildingInsideVisualStudio)' == 'true' "/>
    </Target>

    <Target Name="RunAfterBuild2" AfterTargets="Build">
        <Exec Command="call SelfContained_SingleFile_win-x64_Trimmed_ReadyToRun.cmd" Condition=" '$(BuildingInsideVisualStudio)' == 'true' "/>
    </Target>

</Project>

===Build 16=======================================================================
Location: 
->\ConsoleApp3C\SelfContained_SingleFile_win-x64_ReadyToRun\

Publish mode :
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Single-file; 5)Untrimmed; 6)ReadyToRun; 7)PdbEmbeded; 8)binariesInSingleFile; 9)assembliesCompressed ; 10)NotAot  

Works! App started and it runs properly.

Content:
-1 file
-51 MB

----Use previous project file and this script-------------------
SelfContained_SingleFile_win-x64_ReadyToRun.cmd
echo .NET SDK version:
dotnet --version
dotnet publish ConsoleApp3C.csproj --nologo --no-restore --runtime win-x64 --configuration Release   -p:PublishSingleFile=true -p:SelfContained=true -p:PublishTrimmed=false -p:PublishReadyToRun=true   --output ./SelfContained_SingleFile_win-x64_ReadyToRun

===Build 17=======================================================================
Location: 
->\ConsoleApp3C\SelfContained_SingleFile_win-x64_Trimmed_ReadyToRun\

Publish mode :
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Single-file; 5)Trimmed; 6)ReadyToRun; 7)PdbEmbeded; 8)binariesInSingleFile; 9)assembliesCompressed ; 10)NotAot  

Works! App started and it runs properly.

Content:
-1 file
-12 MB

----Use previous project file and this script-------------------
SelfContained_SingleFile_win-x64_Trimmed_ReadyToRun.cmd
echo .NET SDK version:
dotnet --version
dotnet publish ConsoleApp3C.csproj --nologo --no-restore --runtime win-x64 --configuration Release   -p:PublishSingleFile=true -p:SelfContained=true -p:PublishReadyToRun=true  -p:PublishTrimmed=true --output ./SelfContained_SingleFile_win-x64_Trimmed_ReadyToRun

===Build 18=======================================================================
Location: 
->\ConsoleApp5\bin\Release\net8.0-windows\win-x64\

Publish mode :
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Un-bundled; 5)Untrimmed; 6)NotR2R; 7)PdbEmbeded; 8)binariesNotInSingleFile; 9)assembliesNotCompressed; 10)PublishAot 

Works! App started and it runs properly.

Content:
-228 file
-90 MB

-----Here is project file---------------
<!--ConsoleApp5.csproj +++++++++++++++++++++++++++++++++++++-->
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net8.0-windows</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <PlatformTarget>x64</PlatformTarget>
        <Platforms>AnyCPU;x64</Platforms>
        <RuntimeIdentifier>win-x64</RuntimeIdentifier>
        <!--<DebugType>embedded</DebugType>
        <PublishTrimmed>true</PublishTrimmed>
        <IsTrimmable>true</IsTrimmable>
        <SelfContained>true</SelfContained>
        <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
        <EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
        <PublishSingleFile>true</PublishSingleFile>-->
        <PublishAot>true</PublishAot>
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\ClassLibrary1\ClassLibraryA.csproj" />
    </ItemGroup>

    <Target Name="RunAfterBuild1" AfterTargets="Build">
        <Exec Command="win-x64_Trimmed_AOT.cmd" Condition=" '$(BuildingInsideVisualStudio)' == 'true' "/>
    </Target>

</Project>

===Build 19=======================================================================
Location: 
->\ConsoleApp5\win-x64_Trimmed_AOT\

Publish mode :
1)Release; 2)self-contained; 3)Platform-specific-win-x64; 4)Un-bundled; 5)Trimmed; 6)NotR2R; 7)PdbEmbeded; 8)binariesNotInSingleFile; 9)assembliesNotCompressed; 10)PublishAot 

Works! App started and it runs properly.

Content:
-3 file
-9 MB

----Use previous project file and this script-------------------
win-x64_Trimmed_AOT.cmd
echo .NET SDK version:
dotnet --version
dotnet publish ConsoleApp5.csproj --nologo --no-restore --runtime win-x64 --configuration Release  -p:SelfContained=true  -p:PublishTrimmed=true --output ./win-x64_Trimmed_AOT

==============================================================

3. Code on GitHub

I am putting example build projects on GitHub [99]. There are three solutions.

  • BundleExample01_NET_8.0.0_SDK_8.0.100.sln (read comments; this is broken in .NET 8.0.11)
  • BundleExample01_NET_8.0.11_SDK_8.0.404.sln (locked to SDK_8.0.404)
  • BundleExample01_NET_9.0.0_SDK_9.0.101.sln (locked to SDK_9.0.101)
    Bundle example
    Example 1
    Example 2

4. Conclusion

In this series of articles, we showed 15 different ways to build a .NET8/9 application, depending on the options wanted. There are probably more options or combinations of build properties/flags, but we can call this proof-of-concept testing successful and broad enough. We got most of the build/publish options working properly, according to the documentation.

I was in these articles aiming for some “intermediate level of practical skills” that a modern C#/.NET developer should have. Of course, this is a very interesting topic for every software engineer to get familiar with.

It was a bit of a surprise to discover that build settings are a bit of a “moving target”, and that build tools behavior changed between .NET 8.0.0 and .NET 8.0.11 and that I needed to change my build scripts accordingly.

One very interesting technology offered as a part of .NET8/9 environment is a “ReadyToRun” build option, which is a form of ahead-of-time (AOT) compilation. More details can be found at [7]. Looks to me like a complicated and serious topic, to really understand how it works from the inside. But I do not see the point of really studying it in detail unless you work in Microsoft in their .NET runtime/core department. An average C#/.NET engineer just needs to know how to activate properly the build options and benefits of it.

We also showed how to do a native Ahead-Of-Time compilation (AOT) deployment model. That can be attractive in some cases too.

5. References

[1] .NET application publishing overview

https://learn.microsoft.com/en-us/dotnet/core/deploying/

[2] Self-contained deployment runtime roll forward

https://learn.microsoft.com/en-us/dotnet/core/deploying/runtime-patch-selection

[3] https://www.red-gate.com/products/smartassembly/

[4] https://learn.microsoft.com/en-us/dotnet/core/deploying/single-file/overview?tabs=cli#api-incompatibility

[5] https://www.jetbrains.com/decompiler/

[7] https://devblogs.microsoft.com/dotnet/conversation-about-ready-to-run/

[99] https://github.com/MarkPelf/ArticlesCode , folder 86_Net8BuildModes_Part6