The PublishTrimmed Flag With IL Linker

In a previous post we looked at how we can publish a single exe from a .NET Core project. Now in it, I talk about how the resulting binary is absolutely massive, 70MB for a simple hello world console app! But I also talked about how there are now ways to significantly chop that down.

Despite that, when shared with Reddit, there was some comments that weren’t so impressed. Most notably this gem :

But that’s cool. For Scellow and anyone else that wasn’t impressed with the size of the exe, let’s look at how we can chop it down.

You Need .NET Core 3.0 (Preview 6+)

Like all these features I’m writing about recently, you’re gonna need the very latest version of .NET Core 3.0. At the time of writing it’s Preview 6. Any version earlier will simply not fly. And again, if that isn’t you and you don’t want to muck around with preview versions, then you’ll just have to wait!

PublishedTrimmed Flag

Before we go on, you might hear IL Linker talked about a lot. Possibly because it’s in the title of this post! But that’s because IL Linker is essentially the backbone of this entire feature. However where previous it was this external tool you had to grab from a nuget feed, now it’s built directly into .NET Core 3.0+ which is pretty impressive!

Anyway we previously published our application using the following command :

dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true

And with that, we ended up with an exe over 70MB big :

Not good. But literally all we have to do is add one flag and we can chop it down a bit :

dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true /p:PublishTrimmed=true

So… 29MB. And this is about the time where you go “but shouldn’t this be KB in size?”. And honestly the answer is yes. It should be. But we have to remember that this is still a completely self contained application that doesn’t even require the target machine to know what .NET Core is. So even if we aren’t using things like say.. cryptography so we can get rid of that, there is probably a lot of basic and primitive .NET Core features that we just can’t get rid of.

Still. It’s an exe half the size with no functional difference between the two.

Reflected Assemblies

Through various forms of reflection, we may end up loading assemblies at runtime that aren’t direct references. Take this (very convoluted) example of loading an assembly at runtime :

static void Main(string[] args)
{
    Console.WriteLine(Assembly.Load("System.Security").FullName);
    Console.ReadLine();
}

Now when debugging this locally, and we have .NET Core installed, we ask for System.Security and it knows what that is because we are using the installed .NET Core platform. So running it, we get :

System.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

But if we publish this using the PublishTrimmed flag from the command line, then run it :

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'System.Security, Culture=neutral, PublicKeyToken=null'. 
The system cannot find the file specified.

Unsurprisingly, we have trimmed a bit too much off. Because I don’t actually reference System.Security anywhere, it’s decided we aren’t actually using it. But there is a way to specify that we know best, and to package it up for us.

All we need to do is edit our csproj file for our project and add :

<ItemGroup>
  <TrimmerRootAssembly Include="System.Security" />
</ItemGroup>

Now we will bundle up System.Security with our single exe and everything will run smooth! Pretty nice I have to say!

You may ask yourself “Well how will I know when I need to do this?”. Frankly 99% of the time you won’t. If you decide to trim your exe, you will need to really give it a good test before letting it out into the wild.

2 thoughts on “The PublishTrimmed Flag With IL Linker”

  1. I like that there is an option to pubish our applications to a single-file executable and I am willing to accept that this file is going to be rather large.

    But why don’t we additionally have the option to pubish as a standard clickonce application, allowing users to install it on their machines? This way updates are handled better as well.

    In my version of VS2019 preview there is no option to publish a clickonce application anymore.

    Reply
    • Actually good question. Quick google led me here : https://devblogs.microsoft.com/dotnet/net-core-is-the-future-of-net/ with the quote :

      We are going to recommend MSIX for installation and support for MSIX will be added for Windows 7 so it should work on all the platforms you that .NET Core runs on.

      That surprises me a lot. I haven’t built desktop applications that often, but when I did ClickOnce was very easy to get going. To do all this work to bring desktop apps to .NET Core and then not port what is most likely the most common business deployment scenario (Clickonce) is actually pretty bizarre.

      Reply

Leave a Comment