Русский
Русский
English
Статистика
Реклама

Уменьшить размер консольного .NET 5.0 приложения

Target Framework Moniker

Давайте знакомиться. В .NET 5.0 для использования Windows Forms или WPF нам недостаточно просто указать net5.0:

<PropertyGroup>  <TargetFramework>net5.0</TargetFramework>  <UseWindowsForms>true</UseWindowsForms></PropertyGroup>

При попытке использования Windows Forms или WPF мы получаем ошибку

C:\Program Files\dotnet\sdk\5.0.201\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.DefaultItems.targets(369,5): error NETSDK1136: The target platform must be set to Windows (usually by including '-windows' in the TargetFramework property) when using Windows Forms or WPF, or referencing projects or packages that do so.

Решение, как подсказывает ошибка состоит в указании Target Framework Moniker

<PropertyGroup>  <TargetFramework>net5.0-windows</TargetFramework>  <UseWindowsForms>true</UseWindowsForms></PropertyGroup>

Как это работает

При сборки автоматически импортируются файлы из Microsoft.NET.Sdk\targets.
Далее в dotnet\sdk\5.0\Sdks\Microsoft.NET.Sdk.WindowsDesktop\targets\Microsoft.NET.Sdk.WindowsDesktop.props содержиться код:

    <FrameworkReference Include="Microsoft.WindowsDesktop.App" IsImplicitlyDefined="true"                        Condition="('$(UseWPF)' == 'true') And ('$(UseWindowsForms)' == 'true')"/>    <FrameworkReference Include="Microsoft.WindowsDesktop.App.WPF" IsImplicitlyDefined="true"                        Condition="('$(UseWPF)' == 'true') And ('$(UseWindowsForms)' != 'true')"/>    <FrameworkReference Include="Microsoft.WindowsDesktop.App.WindowsForms" IsImplicitlyDefined="true"                        Condition="('$(UseWPF)' != 'true') And ('$(UseWindowsForms)' == 'true')"/>

Где проблема

Дело в том, что FrameworkReference это транзитивная зависимость: Документ дизайна .NET , Документация NuGet

Это значит, что если у нас есть где-то сборка, которая использует тип из Windows Forms или из WPF мы должны будем все зависимые сборки перевести на 'net5.0-windows'.

Это грозит нам тем, что мы добавляем в резузльтатирующий файл потенциально ненужный хлам.

Если весь код использует Windows Forms или WPF проблемы нет, а если мы в итоге создаём консольное приложение то получаем дополнительные 60МБ при создании самодостаточного файла.

Пример

Библиотека

using System.Windows.Forms;namespace Library{    public class Demo    {        void ShowForm()        {            var f = new Form();            f.Show();        }    }}

Консольное приложение

using System;class Program{    public static void Main()    {        Console.WriteLine("Hello World!");    }}

Обратим внимание, что мы не используем класс Library.Demo.

Соберём самодостаточное приложение с помощью dotnet publish:

dotnet publish ConsoleApp.csproj --self-contained -c Release -r win-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true /p:IncludeAllContentForSelfExtract=true

Результат 81,8МБ !

Благодаря IncludeAllContentForSelfExtract при запуске приложение в %TEMP%\.net мы можем посмотреть из чего оно состоит.

Как же так ?
Мы не использовали Library.Demo, мы указали PublishTrimmed, а Windows Forms к нам пришёл.

Решение

Как видим dotnet publish при обычных настройках не справился со своей работой, поэтому поможем ему !

Шаг 1

В библиотеке укажем вручную зависимость фреймворка и попросим не создавать транзитивную зависимость:

<Project Sdk="Microsoft.NET.Sdk">  <PropertyGroup>    <TargetFramework>net5.0</TargetFramework>    <!-- Укажем зависимости явно -->    <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>  </PropertyGroup>  <ItemGroup>    <!-- .NET Runtime -->    <!-- В данном случае неважно будет PrivateAssets="all" или нет, всегда добавляется при сборке -->    <FrameworkReference Include="Microsoft.NETCore.App" />        <!-- Windows Desktop -->    <!-- PrivateAssets="all" - зависимость не идёт дальше -->    <FrameworkReference Include="Microsoft.WindowsDesktop.App" PrivateAssets="all"  />        <!-- Можно указать и более конкретно:      Microsoft.WindowsDesktop.App.WPF      Microsoft.WindowsDesktop.App.WindowsForms -->  </ItemGroup></Project>

Документация для DisableImplicitFrameworkReference

Ключевая часть PrivateAssets="all". которая не даёт зависимости распространяться дальше.

Шаг 2

Меняем .net5.0-windows на .net5.0 в нашем консольном приложении

Результат

Собираем той же командой:

dotnet publish ConsoleApp.csproj --self-contained -c Release -r win-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true /p:IncludeAllContentForSelfExtract=true

Получаем файл размером всего 18.8МБ со следующим содержимым

Заключение

Стоит ли делать так в библиотеках ?
Однозначно да !
С одной стороны это позволяет использовать типы из Windows Forms или WPF, с другой стороны у сборщика получается выкинуть всё неиспользованное и выдать меньший размер файла.

Источник: habr.com
К списку статей
Опубликовано: 23.03.2021 10:07:12
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Net

C

Net 5

Csharp

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru