As the complexity of .NET projects increases during development, the number of dependent DLL files also gradually grows. This often leads to a cluttered output directory that is not easy to manage or deploy. The NetBeauty2 open-source project was created specifically to solve this problem. It helps developers move .NET runtime and dependent DLL files to a designated directory when publishing a .NET project as self-contained, resulting in a cleaner and tidier output directory.
1. Introduction to NetBeauty2
NetBeauty2 is an open-source .NET dependency organizing tool. Its main purpose is to tidy and optimize the output directory when a .NET project is published as self-contained. With NetBeauty2, developers can easily move .NET runtime and dependent DLL files to a specified directory, making the project's output directory clearer and easier to manage.
Project repository: https://github.com/nulastudio/NetBeauty2
The image below shows the optimized output directory (.NET runtime and referenced dependency libraries moved to the libraries directory; the directory name is configurable):

The image below shows the extremely optimized output directory (see the --hiddens option usage):

For comparison, the image below shows the output directory before using NetBeauty2 (shocking! The .NET runtime and related dependency libraries are all placed in the root output directory. .NET Framework can be configured with privatePath, but .NET Core is not so convenient):

2. Support Status
| NetBeauty 2 | NetCoreBeauty | |
|---|---|---|
| Supported Frameworks | .NET Framework .NET Core 3.0+ |
.NET Core 2.0+ |
| Supported Deployment Modes | Framework-dependent deployment (FDD) Self-contained deployment (SCD) Framework-dependent executables (FDE) |
Self-contained deployment (SCD) |
| Supported Operating Systems | All | win-x64 win-x86 win-arm64 (.NET 6+) linux-x64 linux-arm linux-arm64 osx-x64 osx-arm64 (.NET 6+) |
| Need Patched HostFXR | No / Yes (if using patch) | Yes |
| Minimum Structure | ~20 Files / ~8 Files (if using patch) | ~8 Files |
| How It Works | STARTUP_HOOKS AssemblyLoadContext.Resolving AssemblyLoadContext.ResolvingUnmanagedDll + patched libhostfxr (if using patch) / additionalProbingPaths (if using patch) |
patched libhostfxr additionalProbingPaths |
| Shared Runtime | Yes | Possible if using patched libhostfxr alone |
3. How to Use?
3.1. Preparation
Add the NuGet package to your .NET Core project (the main project to be published):
dotnet add package nulastudio.NetBeauty
Edit the project file (.csproj):
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<BeautySharedRuntimeMode>False</BeautySharedRuntimeMode>
<!-- beauty into sub-directory, default is libs, quote with "" if contains space -->
<BeautyLibsDir Condition="$(BeautySharedRuntimeMode) == 'True'">../libraries</BeautyLibsDir>
<BeautyLibsDir Condition="$(BeautySharedRuntimeMode) != 'True'">./libraries</BeautyLibsDir>
<!-- dlls that you don't want to be moved or can not be moved -->
<!-- <BeautyExcludes>dll1.dll;lib*;...</BeautyExcludes> -->
<!-- dlls that end users never needed, so hide them -->
<!-- <BeautyHiddens>hostfxr;hostpolicy;*.deps.json;*.runtimeconfig*.json</BeautyHiddens> -->
<!-- set to True if you want to disable -->
<DisableBeauty>False</DisableBeauty>
<!-- set to False if you want to beauty on build -->
<BeautyOnPublishOnly>False</BeautyOnPublishOnly>
<!-- DO NOT TOUCH THIS OPTION -->
<BeautyNoRuntimeInfo>False</BeautyNoRuntimeInfo>
<!-- set to True if you want to allow 3rd debuggers(like dnSpy) debugs the app -->
<BeautyEnableDebugging>False</BeautyEnableDebugging>
<!-- the patch can reduce the file count -->
<!-- set to False if you want to disable -->
<!-- SCD Mode Feature Only -->
<BeautyUsePatch>True</BeautyUsePatch>
<!-- App Entry Dll = BeautyDir + BeautyAppHostDir + BeautyAppHostEntry -->
<!-- see https://github.com/nulastudio/NetBeauty2#customize-apphost for more details -->
<!-- relative path based on AppHostDir -->
<!-- .NET Core Non Single-File Only -->
<!-- <BeautyAppHostEntry>bin/MyApp.dll</BeautyAppHostEntry> -->
<!-- relative path based on BeautyDir -->
<!-- .NET Core Non Single-File Only -->
<!-- <BeautyAppHostDir>..</BeautyAppHostDir> -->
<!-- <BeautyAfterTasks></BeautyAfterTasks> -->
<!-- valid values: Error|Detail|Info -->
<BeautyLogLevel>Info</BeautyLogLevel>
<!-- set to a repo mirror if you have trouble in connecting github -->
<!-- <BeautyGitCDN>https://gitee.com/liesauer/HostFXRPatcher</BeautyGitCDN> -->
<!-- <BeautyGitTree>master</BeautyGitTree> -->
</PropertyGroup>
<ItemGroup>
<PackageReference Include="nulastudio.NetBeauty" Version="2.1.4.4" />
</ItemGroup>
</Project>
Run dotnet build or dotnet publish; the output optimization will be performed automatically.
3.2. If the Application Has Already Been Published?
If your application has already been published, you can use it like this (the site owner hasn't tried it; this can be a post-publishing remedy):
Usage:
nbeauty2 [--loglevel=(Error|Detail|Info)] [--srmode] [--enabledebug] [--usepatch] [--hiddens=hiddenFiles] [--noruntimeinfo] [--roll-forward=<rollForward>] [--apphostentry=<appHostEntry>] [--apphostdir=<appHostDir>] <beautyDir> [<libsDir> [<excludes>]]
For example:
ncbeauty2 --usepatch --loglevel Detail --hiddens "hostfxr;hostpolicy;*.deps.json;*.runtimeconfig*.json" /path/to/publishDir libraries "dll1.dll;lib*;..."
3.3. Configure as a .NET Core Global Tool
dotnet tool install --global nulastudio.nbeauty
After installation, it will be automatically applied when publishing a project.
4. Usage Examples for Various Project Types
Clone the repository (https://github.com/nulastudio/NetBeauty2); it contains usage examples for various template projects:

| Test Project Name | Description |
|---|---|
| WPFTest | WPF project (similar to WinForms), default .NET 5 |
| WebAppTest | Razor Pages project, default .NET 6 |
| NetFxTest | .NET Framework WPF project (.NET 4.x, similar to WinForms) |
| ChromelyTest | .NET project referencing Chromely |
| AvaloniaTest | Avalonia UI project, default .NET 5 |
Tip 1
The Chromely NuGet package is a library for creating cross-platform desktop applications. It provides a Chromium-based browser control. With Chromely, developers can use web technologies (such as HTML, CSS, and JavaScript) to build desktop application user interfaces while retaining access to local system resources.
The Chromely NuGet package offers a complete set of APIs and tools, allowing developers to easily convert web applications into desktop applications without extensive code rewriting or modification. It also supports various plugins and extensions, enabling developers to add extra functionality or customize existing features as needed.
Additionally, Chromely supports multiple programming languages and frameworks, such as C#, .NET Core, and ASP.NET Core, so developers can choose the technology stack they are most familiar with to build applications.
Tip 2
Avalonia UI is a cross-platform .NET UI framework that allows developers to use XAML and C# to create applications that can run on multiple platforms, including Windows, Linux, macOS, iOS, Android, and WebAssembly. Avalonia UI aims to help developers build beautiful, modern graphical user interfaces (GUIs). It is compatible with all platforms that support .NET Standard 2.0, enabling developers to create native applications for multiple operating systems from a single codebase. By using Avalonia UI, developers can leverage the full power of the .NET ecosystem while achieving cross-platform compatibility, reducing development costs and improving efficiency.
Recommended open-source control libraries: irihitech/Semi.Avalonia, irihitech/Ursa.Avalonia
5. Summary
Lin Dexi shared a similar package: NuGet Gallery | dotnetCampus.PublishFolderCleaner 3.11.1. However, that library claims to support only Windows publishing. You can compare them. Original article: PublishFolderCleaner让你的dotnet应用发布文件夹更加整洁 - lindexi - 博客园 (cnblogs.com). Here is the open-source repository for NetBeauty2 again:
Project repository: https://github.com/nulastudio/NetBeauty2
References: