Комментарии 34
Не понял проблему, если честно.
Попробуйте, проект не соберётся.
error NETSDK1136: The target platform must be set to Windows (usually by including '-windows' in the TargetFramework property).
В проекте написано:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<RootNamespace>_548442</RootNamespace>
</PropertyGroup>
</Project>
Компилируется да. А теперь попробуйте dotnet publish —self-contained.
У меня не собирается:
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 может внутри использовать рефлексию, тримминг испортил бы приложение.
Берем ту версию, которая предустановлена на вашем парке машин и получаем считанные десятки килобайт.
В любом случае это достаточно древней фреймворк, чтобы некоторые необходимые библиотеки не работали с ними.
Кроме того, бывают случаи когда целенаправленно клиенты убирают .NET для безопасности.
Windows 7 поддерживает версии выше.
Так что никакой универсальности с .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 ставится из нугета отдельно...
Ммм. И зачем же он по отдельности? Может есть способ без него обойтись?
Ну если ломать API и жизнь всем пользователям то можно рефакторить и поделить на части с зависимостями от WinForms и без.
Но это радикальный шаг, а хотелось решения без изменения кода.
Это был System.Windows.Media.Imaging.BitmapSource
Ну если ломать API и жизнь всем пользователям то можно рефакторить и поделить на части с зависимостями от WinForms и без.
Это тип wpf, но наверное вы это и имели ввиду.
Если проект на стадии умирания и есть только поддержка текущих клиентов, без новых фич и всего такого, то такой подход имеем место быть.
Но если проект развивается, появляются новые клиенты, делаются фичи, то почему не нужно исправлять недоработки архитектуры?
Имхо да, разделить на либы на 2 типа, а текущее API например оставить как враппер над ними для старых версий (при этом заобсолетив его) — вполне себе хорошее решение.
Ещё можно поставить p:TrimmingMode=Link и обрезать все неиспользуемое. Особенно актуально для консольных приложух. Но WPF и WinForms кажется сейчас ломаются на этом.
Ещё будет хорошей опцией отключить неиспользуемые фичефлаги дотнета. Это ещё минус несколько мегабайт.
Ну и если таргет только винда, то можно добавить линк на NativeAOT (бывший Core RT) и получить консольную в районе 4Мб для большого приложения.
Учитывая количество проблем, думаю рановато будет https://github.com/dotnet/runtimelab/labels/area-NativeAOT
Почти всё что есть в этом списке — фиче реквесты и улучшения, такие как поддержка 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.
Ещё будет хорошей опцией отключить неиспользуемые фичефлаги дотнета. Это ещё минус несколько мегабайт.
Не подскажите какие?
Может я не всё включил у себя.
Я имею ввиду 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
Уменьшить размер консольного .NET 5.0 приложения