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

Автор Сообщение
news_bot ®

Стаж: 6 лет 3 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
23-Мар-2021 12:32

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
===========

Похожие новости: Теги для поиска: #_.net, #_c#, #_.net_5, #_.net, #_csharp, #_.net, #_c#
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 17-Май 14:10
Часовой пояс: UTC + 5