Как стать автором
Обновить

Комментарии 34

А зачем в итоге помечать проект как использующий WPF, если он этого не делает? Чтобы получить лишние dll в результирующую сборку?

Не понял проблему, если честно.

Попробуйте, проект не соберётся.


error NETSDK1136: The target platform must be set to Windows (usually by including '-windows' in the TargetFramework property).

Взял последнюю студию, создал там новый консольный проект с Hello World, он отлично скомпилился.
В проекте написано:
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <RootNamespace>_548442</RootNamespace>
  </PropertyGroup>

</Project>

Компилируется да. А теперь попробуйте dotnet publish —self-contained.

Отлично публикуется и запускается вот с такими настройками (лень искать, во что они там в консольном запуске прокидываются):
image
А в библиотеке выставлен net5.0-windows?
У меня не собирается:

Library.csproj
<Project Sdk="Microsoft.NET.Sdk">

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


ConsoleApp.csproj
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\Library\Library.csproj" />
  </ItemGroup>
</Project>


error NU1201: Project Library is not compatible with net5.0 (.NETCoreApp,Version=v5.0). Project Library supports: net5.0-windows7.0 (.NETCoreApp,Version=v5.0)
А, вот теперь я только понял, что и зачем вы делаете. В статье явно нигде не написано, что проекты друг от друга зависят.

В такой связке консольное приложение перестает билдится, пишет
Error		Project '..\548442WPF\548442WPF.csproj' targets 'net5.0-windows'. It cannot be referenced by a project that targets '.NETCoreApp,Version=v5.0'.	548442	MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets	1720	
Error	NU1201	Project 548442WPF is not compatible with net5.0 (.NETCoreApp,Version=v5.0). Project 548442WPF supports: net5.0-windows7.0 (.NETCoreApp,Version=v5.0)	548442	548442\548442.csproj	1	


Но всё это на мой взгляд логично — WPF и WinForms не кроссплатформенные, поэтому у них свои таргеты. То, что объем консольного приложения увеличивается на сборки WPF в такой ситуации — тоже логично, WPF может внутри использовать рефлексию, тримминг испортил бы приложение.

Спасибо, уточню в статье раз было неясно.
Оно то логично, но потом почему-то с урезанием неиспользованного кода не вырезается весь WinForms, который нигде по факту не используется.

Не стоит делать отсылку к прошлым эпохам.
Дело же не в .net5, а в независимой от рантайма (self-contained) сборке. Если собирать как обычно, получим те же считанные килобайты.
С таким подходом придётся либо работать с .NET 3.5 (если нужно Windows 7) или .NET 4.0.
В любом случае это достаточно древней фреймворк, чтобы некоторые необходимые библиотеки не работали с ними.
Кроме того, бывают случаи когда целенаправленно клиенты убирают .NET для безопасности.
Вы что-то путаете, это Windows XP максимум работает с .Net 4.0
Windows 7 поддерживает версии выше.
С .NET Framework 3.5 все ещё хуже: у него среда выполнения (CLR) своя (.NET 2.0) с CLR от 4.0 (которую используют все последующие версии) она несовместима ни в ту, ни в другую сторону. Поэтому для приложений, сделанных под 3.5, на новых версиях Windows приходится устанавливать отдельно .NET 3.5 из компонентов. А, к примеру, уже в Windows Server 2012 R2 этот компонент физически удален из устанавливаемого образа (осталась только ссылка), и его нужно ставить из другого источника (впрочем, на дистрибутивном диске он лежит, так что далеко ходить не надо).
Так что никакой универсальности с .NET 3.5, чтобы оно работало из коробки начиная с Win7 до наших дней, все равно не получится.
Конечно получится.
Делаем приложение на 3.5.
Прописываем такой app.exe.config:

<configuration>
 <startup>
    <supportedRuntime version="v4.0" />
    <supportedRuntime version="v2.0.50727"/>
 </startup>
</configuration>


Приложение запускается с .NET 4 или выше если находит либо с .NET 3.5 (рантайм 2.0).
Это решение работает уже многие годы.

В небольших очень редких случаях есть различное поведение между 3.5 и 4.0.
Да, пардон, забыл про это. И самое обидное, что я про этот параметр в документации некогда читал.

Хотя бы потому что предустановленная версия медленнее работает ибо сильно устарела.


Так же нет некоторых фич. Те же Span-ы как зависимость подключать надо и они потянут дофига всего как отдельные либы лежащие рядом. Кроме того нет нормального self-contained. Ну и консольное приложение не запустить на линукс и мак одним бинарен без плясок с бубном.


Не вижу ни единой причины сейчас начинать новый проект на старом .Net Framework.

Ммм… а зачем вообще библиотека, которая таргетит net5.0-windows? Зачем библиотека, которая работает с формами? Я интересуюсь.


Да и таргетить сам пятый дотнет… только если используете фичи нового рантайма. Иначе это будет избавление от потенциальных пользователей с более низким таргетом.

TFM не ограничивается только формами.
Так получилось, что в библиотеке в одной из внутренних зависимостей используется тип из WinForms.
А раз он используется внутри, то вся библиотека затребовала windows TFM и в результате бинарник разбух без хорошей причины.

что в библиотеке в одной из внутренних зависимостей используется тип из WinForms.

Как-то подозрительно). А какой тип?

Тип System.Drawing.Bitmap.
Библиотека для работы с WinAPI.


Несомненно проблема такого плана не возникает у всех каждый день.
Тем более, что такой проблемы не было до появления .NET 5, а на него, полагаю, перешли не все.

Для Bitmap не нужны формы… Bitmap ставится из нугета отдельно...

Промахнулся с типом. Это был System.Windows.Media.Imaging.BitmapSource.

Ммм. И зачем же он по отдельности? Может есть способ без него обойтись?

Ну если ломать API и жизнь всем пользователям то можно рефакторить и поделить на части с зависимостями от WinForms и без.
Но это радикальный шаг, а хотелось решения без изменения кода.

Это был System.Windows.Media.Imaging.BitmapSource
Ну если ломать API и жизнь всем пользователям то можно рефакторить и поделить на части с зависимостями от WinForms и без.

Это тип wpf, но наверное вы это и имели ввиду.


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


Но если проект развивается, появляются новые клиенты, делаются фичи, то почему не нужно исправлять недоработки архитектуры?


Имхо да, разделить на либы на 2 типа, а текущее API например оставить как враппер над ними для старых версий (при этом заобсолетив его) — вполне себе хорошее решение.

Ещё можно поставить p:TrimmingMode=Link и обрезать все неиспользуемое. Особенно актуально для консольных приложух. Но WPF и WinForms кажется сейчас ломаются на этом.


Ещё будет хорошей опцией отключить неиспользуемые фичефлаги дотнета. Это ещё минус несколько мегабайт.


Ну и если таргет только винда, то можно добавить линк на NativeAOT (бывший Core RT) и получить консольную в районе 4Мб для большого приложения.

Почти всё что есть в этом списке — фиче реквесты и улучшения, такие как поддержка arm64 или, например, реквест на добавить возможность компилить в .sys.


Для сравнения такой же список самого dotnet runtime (over 5к и большАя часть — баги) https://github.com/dotnet/runtime/issues


Что касается рановато, то тут каждый решает сам для себя конечно. Я к примерю юзаю эту штуку для inhouse консольных тулов, начиная с .net core 2.1, когда ещё не было single file publishing фичи. За всё время была только 1 раз проблема с тем что при выводе на консоль float числа, последняя цифра выводилась на 1 больше. И то узнали об это при сравнении с новой версией.


Основная проблема имхо в том что NativeAOT не умеет в кроскомпиляцию. И если вам нужна версия под мак, то с NativeAOT вам нужен будет билдер на mac'е.


Ну и надо быть готовым к тому что формат флажков пока что может поменяться, как это было при отмирании CoreRT.

Пока нет официальной поддержки, я пока не готов рисковать.
Без Native AOT и так попадаем на баги .NET-а :)

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

Не подскажите какие?
Может я не всё включил у себя.

Я имею ввиду feature switches (https://github.com/dotnet/runtime/blob/main/docs/workflow/trimming/feature-switches.md)


По умолчанию они включены, но если вы что то не используете, то можете отключить. Ну и соответственно часть либов перестанет поставляться вместе с итоговым файлом. Даже при включенном TrimMode=link, некоторые из них дают по 0.5-1Мб оверхеда, а без него и того больше.


Так например вы вероятно не используете UnsafeUTF7Encoding или UnsafeBinaryFormatterSerialization. А в release конфигурации наверняка можете отключить DebuggerSupport полностью, а не только символы.


Важно только знать что некоторые опции (например InvariantGlobalization) нужно наоборот включать, что бы Globalization функциональность отрезалась.

Это знакомо, я уже думал, что-то ещё упустил.

С UnsafeBinaryFormatterSerialization=false нужно быть острожным.
Внезапно продукты MS (хе-хе) не работают без него. Т.е. всё собирается без проблем но падает самым непредсказуемым образом: github.com/PowerShell/PowerShell/issues/14054
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории