I’ve come to finding it somewhat amusing, that if you build a fresh .NET project, like,
dotnet publish ./Blah.csproj ... -c Release -p:PublishSingleFile=true
that the published “Single File” contains of quite a handful of files. So do I, having studied physics and all that, have an outdated knowledge of the concept of “single”? Or is there a very specific reason for any of the files that appear that and it just has to be?
I really needed to figure that out for a small web server application (so, ASP.NET), and as we promised our customer a small, simple application; all the extra non-actually-single files were distracting spam at least, and at worst it would suggest a level of complexity to them that wasn’t helpful, or suggest a level of we-don’t-actually-care when someone opens that directory.
So what I found to do a lot was to extend my .csproj file with the following entries, which I want to explain shortly:
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<DebugSymbols>false</DebugSymbols>
<DebugType>None</DebugType>
</PropertyGroup>
<PropertyGroup>
<PublishIISAssets>false</PublishIISAssets>
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup Condition="'$(Configuration)'=='Release'">
<Content Remove="*.Development.json" />
<Content Remove="wwwroot\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="wwwroot\**" />
</ItemGroup>
- The first block gets rid of any
*.pdbfile, which stands for “Program Debug Database” – these contain debugging symbols, line numbers, etc. that are helpful for diagnostics when the program crashes. Unless you have a very tech-savvy customer that wants to work hands-on when a rare crash occurs, end users do not need them. - The Second block gets rid of the files
aspnetcorev2_inprocess.dllandweb.config. These are the Windows “Internet Information Services” module and configuration XML that can be useful when an application needs tight integration with the environmental OS features (authentication and the likes), but not for a standalone web application that just does a simple thing. - And then the last two blocks can be understood nearly as simple as they are written – while a customer might find an
appsettings.jsonuseful, anyappsettings.Development.jsonis not relevant in their production release, - and for a ASP.NET application, any web UI content conventionally lives in a
wwwroot/folder. While the app needs them, they might not need to be visible to the customer – so the combination of <Content Remove…/> and <EmbeddedResource Include…/> does exactly that.
Maybe this can help you, too, in publishing cleaner packages to your customers, especially when “I just want a simple tool” should mean exactly that.

