Posted on 25. June 2019

Выпуск .NET Core 3.0 Preview 5

Совсем недавно вышел .NET Core 3.0 Preview 5. Он содержит новый Json сериализатор, поддержку публикации исполняемых файлов из одного файла, обновление для отката времени выполнения и изменения в BCL. Не забудьте ознакомиться с улучшениями в .NET Core 3.0 Preview 4.

Загрузите .NET Core 3.0 Preview 5 на Ваш Windows, macOS и Linux уже сейчас.

Также были обновлены ASP.NET Core и EF Core.

WPF и Windows Forms Обновления

Вы должны увидеть улучшение производительности при запуске  WPF и Windows Forms. Сборки WPF и Windows Forms теперь скомпилированы заранее, с использованием crossgen. Многие пользователи уже заметили улучшения при запуске между Preview 4 и Preview 5.

Было опубликовано больше WPF кода как часть .NET Core 3.0 Preview 4. Уже в Preview 7 будет окончательная WPF публикация.

Новый SqlClient

SqlClient - это поставщик данных, который Вы используете для доступа к SQL Server и базе данных SQL Azure либо через один из популярных .NET O/RM, например EF Core или Dapper, либо напрямую через API-интерфейсы ADO.NET.

В течение многих лет SqlClient поставлялся как часть сборки System.Data.dll в .NET Framework. Каждый раз, когда для использования новых функций SQL Server требовались изменения в SqlClient, приходилось ждать возможности, чтобы обновить .NET Framework на Windows. Раньше это работало нормально, поскольку новые функции SQL Server по-прежнему регулярно выпускались, разработка новых функций переходила на .NET Core и все вело к улучшению стабильности .NET Framework, и было больше смысла выводить разработку SqlClient из-под диапазона.

Введите Microsoft.Data.SqlClient, новую версию SqlClient, которую Вы можете добавить как NuGet пакет в .NET Framework и .NET Core (включая .NET Core 3.0) приложениях, которые сегодня запускаются в режиме предварительного просмотра.

Что нового в Microsoft.Data.SqlClient?

Отсутствие поддержки Always Encrypted в .NET Core было основной проблемой, которая была решена в этом предварительном просмотре.

Также ведется работа над двумя новыми функциями, доступными как для .NET Framework, так и для .NET Core:

  • Классификация данных
  • Поддержка UTF-8

В настоящее время планируется выпустить эти и другие улучшения в Microsoft.Data.SqlClient в те же сроки, что и в .NET Core 3.0.

Что значит для System.Data.SqlClient?

System.Data.SqlClient по-прежнему будет поддерживаться и получать важные обновления безопасности, поэтому нет необходимости перемещения, если Ваше приложение взаимодействует с ним. Но если Вы хотите воспользоваться новыми функциями, Вам следует рассмотреть обновление к Microsoft.Data.SqlClient. Процесс должен быть простым для многих приложений: просто установите пакет и обновите пространство SqlClient имен в Вашем коде. В некоторых других случаях потребуются изменения в конфигурации или обновленных O/RM версиях, которые зависят от нового SqlClient.

Следите за этим блог постом, чтобы узнать больше информации о новом SqlClient.

Публикация отдельных EXE-файлов

Теперь Вы можете публиковать однофайловый исполняемый файл с помощью dotnet publish. Эта форма одиночного EXE-файла - фактически самораспаковывающийся исполняемый файл. Он содержит все зависимости, включая нативные зависимости, в качестве ресурсов. При запуске он копирует все зависимости во временный каталог и загружает их туда. Распаковать зависимости нужно всего один раз. После этого запуск происходит быстро и просто.

Вы можете включить этот параметр публикации, добавив свойство PublishSingleFile в файл проекта или добавив новый параметр в командной строке.

К примеру, чтобы создать отдельное EXE-приложение для 64-разрядной Windows версии:

dotnet publish -r win10-x64 /p:PublishSingleFile=true

Отдельные EXE-приложения должны соответствовать архитектуре. В результате необходимо указать идентификатор времени выполнения.

Смотрите Single file bundler для получения дополнительной информации.

Триммер сборки, преждевременная компиляция (через кроссген) и объединение отдельных файлов - новые функции в .NET Core 3.0, которые можно использовать вместе или по отдельности. Ожидайте услышать больше об этих трех особенностях в будущих preview-версиях.

Ожидается, что многие из Вас предпочтут один exe-файл, предоставляемый заранее установленным компилятором, а не самораспаковывающийся-исполняемый подход в .NET Core 3.0. Опережающий подход к компиляции будет предоставлен как часть .NET 5 выпуска.

JSON Сериализатор

Новый JSON сериализатор расположен поверх высокопроизводительных Utf8JsonReader и Utf8JsonWriter. Он десериализует объекты из JSON и сериализует объекты в JSON. Выделение памяти минимально и включает в себя поддержку чтения и записи JSON с Stream в асинхронном режиме.

Для начала используйте JsonSerializer класс в пространстве System.Text.Json.Serialization имен. Смотрите документацию с дополнительной информацией и примерами. Набор функций продолжает расширяться для будущих preview-версий.

Изменение дизайна Utf8JsonWriter

Основываясь на отзывах об удобстве использования и надежности, был внесен ряд изменений в Utf8JsonWriter дизайн, который был добавлен во второй preview-версии. Writer теперь является обычным классом, а не ref структурой, и реализует IDisposable. Это позволяет добавлять поддержку записи в потоки напрямую. Кроме того, был удален JsonWriterState, и теперь JsonWriterOptions необходимо передавать непосредственно в Utf8JsonWriter, который поддерживает свое собственное состояние. Чтобы помочь компенсировать распределение, Utf8JsonWriter имеет новый API сброса, который позволяет Вам сбросить его состояние и повторно использовать модуль записи. Также была добавлена встроенная реализация IBufferWriter<T> с именем ArrayBufferWriter<T>, которую можно использовать с Utf8JsonWriter. Вот фрагмент кода, который показывает изменения:

// New, built-in IBufferWriter that's backed by a grow-able array
var arrayBufferWriter = new ArrayBufferWriter();
 
// Utf8JsonWriter is now IDisposable
using (var writer = new Utf8JsonWriter(arrayBufferWriter, new JsonWriterOptions { Indented = true }))
{
 
   // Write some JSON using existing WriteX() APIs.
 
   writer.Flush(); // There is no isFinalBlock bool parameter anymore
}

Вы можете прочитать больше об изменении дизайна здесь.

Index и Range

В предыдущем предварительном просмотре платформа поддерживала Index и Range, предоставляя перегрузки общих операций, таких как индексаторы и методы, такие как Substring, которые принимали значения Index и Range. Основываясь на отзывах пользователей, все было упрощено и позволило компилятору вызывать существующие индексаторы. В документе «Index и Range изменения» содержится более подробная информация о том, как это работает, но основная идея заключается в том, что компилятор может вызывать индексатор на int основе, извлекая смещение из заданного значения Index. Это означает, что индексирование с использованием Index теперь будет работать для всех типов, которые предоставляют индексатор и имеют Count или Length свойство. Компилятор обычно не может использовать существующий индексатор для Range, потому что он возвращает только единичные значения. Однако теперь компилятор разрешает индексирование с использованием Range, когда тип предоставляет индексатор, который принимает Range, или Slice метод. Это позволяет Вам выполнять индексацию с использованием Range, а также работать с интерфейсами и типами, которые Вы не контролируете, предоставляя метод расширения.

Существующий код, использующий эти индексаторы, будет продолжать компилироваться и работать, как ожидается. Смотрите пример в этом коде:

string s = "0123456789";
char lastChar = s[^1]; // lastChar = '9'
string startFromIndex2 = s[2..]; // startFromIndex2 = "23456789"

Следующие String методы были удалены:

public String Substring(Index startIndex);
public String Substring(Range range);

Любой код, использующий эти String методы, должен быть обновлен для использования индексаторов

string substring = s[^10..]; // Replaces s.Substring(^10);
string substring = s[2..8];   // Replaces s.Substring(2..8);

Следующий Range метод ранее возвращал OffsetAndLength:

public Range.OffsetAndLength GetOffsetAndLength(int length);

Теперь он просто вернет строку:

public ValueTuple GetOffsetAndLength(int length);

Здесь продолжается компиляция и запуск, как и раньше:

(int offset, int length) = range.GetOffsetAndLength(20);

Новая японская эра (Reiwa)

1 мая 2019 года в Японии началась новая эра - так называемая Reiwa. Программное обеспечение, поддерживающее японские календари, например .NET Core, должно быть обновлено в соответствии с требованиями Reiwa. .NET Core и .NET Framework были обновлены и корректно обрабатывают японское форматирование и парсинг даных.

.NET полагается на операционную систему или другие обновления для правильной обработки Reiwa данных. Если Вы или Ваши клиенты используете Windows, загрузите последние Windows обновления. Если Вы используете macOS или Linux, загрузите и установите ICU 64.2 версию, которая поддерживает новую японскую эру.

В блог посте "Управление и переход к новой эре в японском календаре" содержит больше информации об изменениях, внесенных в .NET для поддержки новой японской эры.

Внутренние аппаратные API изменения

Avx2.ConvertToVector256* методы были изменены, чтобы возвращать подписанный тип, а не неподписанный. Это помещает их в строку с Sse41.ConvertToVector128* методами и соответствующими встроенными функциями. Например, Vector256<ushort> ConvertToVector256UInt16(Vector128<byte>) теперь является Vector256<short> ConvertToVector256Int16(Vector128<byte>).

Sse41/Avx.ConvertToVector128/256* методы были разделены на методы, которые принимают Vector128/256<T>, и методы, которые принимают T*. Например, ConvertToVector256Int16(Vector128<byte>) теперь поддерживает перегрузку ConvertToVector256Int16 (byte*). Это было сделано потому, что основная инструкция, которая принимает адрес, выполняет частичное векторное чтение (а не полное векторное или скалярное чтение). Это означало, что генерирация оптимального кодирования команд не всегда была возможной и пользователю приходилось выполнять чтение из памяти. Это разделение позволяет пользователю явно выбирать форму адресации инструкции при необходимости (например, когда у Вас еще нет Vector128<T>).

Записи перечисления FloatComparisonMode и Sse/Sse2.Compare методы были переименованы, чтобы уточнить, что операция упорядочена / неупорядочена. Они также были переупорядочены для обеспечения большего взаимодействия между SSE и AVX реализациями. Например, Sse.CompareEqualOrderedScalar теперь является Sse.CompareScalarOrderedEqual. Аналогично, для AVX версий Avx.CompareScalar (left, right, FloatComparisonMode.OrderedEqualNonSignalling) теперь Avx.CompareScalar(left, right, FloatComparisonMode.EqualOrderedNonSignalling).

Обновление политики среды выполнения .NET Core

Среда выполнения .NET Core, фактически связная среда, теперь позволяет выполнять откат до основной версии. Средство выполнения уже включает откат на исправление и второстепенные версии в качестве политики по умолчанию. В планах - не добавлять откат основной версии в качестве политики по умолчанию, хотя это важно для некоторых сценариев.

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

Существует новый RollForward, который принимает следующие значения:

  • LatestPatch — Переход к самой высокой версии. Это отключит второстепенный откат версии.
  • Minor — Переход к самой меньшей минорной версии, если запрашиваемая минорная версия отсутствует. Если запрашиваемая дополнительная версия присутствует, используется LatestPatch политика. Это политика по умолчанию.
  • Major — Переход к самой меньшей высокой версии и меньшей минорной версии, если запрашиваемая основная версия отсутствует. Если запрашиваемая основная версия присутствует, то используется дополнительная Minor политика.
  • LatestMinor — Переход к большей минорной версии, даже если запрошенная минорная версия присутствует.
  • LatestMajor — Переход к большей и большей минорной версии, даже если присутствует запрашиваемая главная версия.
  • Disable — Не откатывайтесь заранее. Привязывайтесь только к указанной версии. Эта политика не рекомендована для общего использования, так как она отключает возможность перехода к последним исправлениям. Рекомендуется только для тестирования.
Для получения дополнительной информации изучите блог посты Runtime Binding Behavior и dotnet/core-setup #5691.

Уменьшение докерных изображений .NET Core для Linux

Размер среды выполнения был сокращен примерно на 10 МБ, с помощью функции «частичного кроссгена».

По умолчанию, когда заранее компилируются сборки, также компилируются и все методы. Эти нативные скомпилированные методы увеличивают размер сборки, иногда очень сильно (затраты довольно изменчивы). Во многих случаях при запуске используется подмножество, иногда небольшое подмножество методов. Это означает, что затраты и выгода могут быть асимметричными. Частичный кроссген позволяет предварительно скомпилировать только те методы, которые имеют значение.

Запустите несколько .NET Core приложений и соберите данные о том, какие методы вызываются. Этот процесс называется «обучение». Обучающие данные называются «IBC» и используются в качестве входных данных для перекрестного анализа, чтобы определить, какие методы компилировать.

Этот процесс полезен только в том случае, если Вы изучаете продукт с помощью представительных приложений. В противном случае это может повредить запуск. В настоящее время поставлена цель, сделать образы Docker контейнеров для Linux меньше. В результате, получится только .NET Core сборка для Linux, которая меньше по размеру и где был использован частичный кроссген. Это позволяет изучать .NET Core с меньшим набором приложений, потому что сценарий относительно узок. Это обучение было сосредоточено на .NET Core SDK (например, на запуске dotnet сборки и тестировании dotnet), приложениях ASP.NET Core и PowerShell.

В будущих выпусках будет расширено использование частичного кроссгена.

Docker Обновления

Теперь поддерживаются Alpine ARM64 образы. Также Linux образ по умолчанию переключен на Debian 10 / Buster. Debian 10 еще не выпущен. Есть вероятность, что он будет выпущен до .NET Core 3.0.

Добавилась поддержка Ubuntu 19.04 / Disco. Обычно не добавляется поддержка выпусков Ubuntu, не относящихся к LTS, но поддержка 19.04 была добавлена как часть процесса готовности к Ubuntu 20.04, следующей версии LTS. Поддержка для 19.10 будет добавлена при его выпуске.

О том, как использовать .NET Core и Docker вместе, Вы можете ознакомиться подробно здесь.

Обновления AssemblyLoadContext

AssemblyLoadContext продолжает улучшаться, чтобы в будущем простые модели плагинов работали без особых усилий (или кода) с Вашей стороны, и чтобы были возможны сложные модели плагинов. В Preview 5 была добавлена неявная загрузка типов и сборок через Type.GetType, когда вызывающая сторона не является приложением, например, сериализатором.

См. документ AssemblyLoadContext.CurrentContextualReflectionContext для получения дополнительной информации.

COM-вызываемые управляемые компоненты

Теперь Вы можете создавать управляемые COM-компоненты в Windows. Эта возможность очень важна для использования .NET Core с моделями COM надстроек, а также для обеспечения паритета с .NET Framework.

В .NET Framework использовался mscoree.dll в качестве COM-сервера. Вместе с .NET Core мы предоставляем встроенную библиотеку DLL запуска, которая добавляется в каталог bin компонента при сборке COM-компонента.

Изучите COM Server Demo, чтобы опробовать эту новую возможность.

Поддержка больших GC страниц

Большие страницы (также известные как «Огромные страницы на Linux») - это функция, при которой операционная система может устанавливать области памяти, превышающие собственный размер страницы (часто 4 КБ), чтобы повысить производительность приложения, запрашивающего эти большие страницы.

Когда происходит преобразование виртуального адреса в физический, сначала обращаются к кэшу, называемому буфером просмотра трансляции (TLB), чтобы проверить, доступен ли физический перевод для виртуального адреса, к которому осуществляется доступ, чтобы избежать создания таблицы страниц. Каждый перевод большой страницы использует один буфер перевода внутри процессора. Размер этого буфера обычно на три порядка больше размера собственной страницы; это увеличивает эффективность буфера трансляции, что может повысить производительность часто используемой памяти.

Теперь GC можно настроить с помощью GCLargePages в качестве опции для выбора размещения больших страниц на Windows. Использование больших страниц уменьшает количество TLB пропусков, поэтому потенциально может повысить производительность приложений. Это, однако, идет с некоторыми ограничениями.

В заключении

Обязательно попробуйте новый выпуск .NET Core 3.0. Пожалуйста, делитесь Вашими отзывами или комментариями на GitHub. Ваш вклад важен для будущего развития!

Взгляните на .NET Core 3.0 Preview 1, Preview 2, Preview 3 и Preview 4, если Вы пропустили эти выпуски. В этом посте Вы можете узучить полный набор новых возможностей, которые были добавлены к выпуску .NET Core 3.0.



Exception: Stack empty.
Posted on 11. June 2019

Перемещение образца WPF приложения на .NET Core 3 (Часть 1)

Ольга Гавриш недавно написала пост о том, как перенести WinForms приложение с .NET Framework на .NET Core. В этом блог посте будут выполняться шаги по переносу WPF-приложения на .NET Core 3. Многие из этих шагов будут знакомы Вам из поста Ольги, но здесь добавлены некоторые дополнительные общие зависимости, с которыми пользователи могут столкнуться, например, использование WCF  клиента или сторонних пакетов пользовательского интерфейса.

Чтобы этот пост не был слишком длинным, он разбит на две части. В первой части будет выполнена подготовка к перемещению и созданию нового csproj файла для .NET Core версии приложения. Во втором посте будут добавлены реальные изменения в коде, необходимые для работы приложения на .NET Core.

Эти блог посты не посвящены какой-либо конкретной проблеме переноса. В них описываются шаги, необходимые для переноса WPF приложения. Если есть конкретные темы по миграции на .NET Core, которые Вы хотели бы изучить более детально, сообщите об этом в комментариях.

Видео инструкции

Если предпочитаете видео инструкции по перемещению приложения, Вы можете просмотреть ролики на YouTube, посвященный переносу приложения.

О примере

Для этого примера было написано простое приложение для торговли товарами под названием «Bean Trader». У пользователей приложения есть учетные записи с разным количеством бобов (которые бывают четырех разных цветов). С этим приложением, пользователи могут предлагать и принимать сделки с другими пользователями. Приложение не очень большое (около 2000 строк кода), но, с точки зрения сложности, на шаг впереди «Hello World». Оно создано для того, чтобы Вы могли видеть некоторые проблемы, с которыми пользователи могут столкнуться при переносе реальных приложений.

Интересные зависимости в приложении:

  • Соединение WCF с бэкенд-трейдингом через двойной NetTcp канал
  • Моделирование пользовательского интерфейса и MahApps.Metro диалогов
  • Внедрение зависимостей с помощью Castle.Windsor (хотя, многие DI-решения, включая Microsoft.Extensions.DependencyInjection, могут использоваться в этом сценарии)
  • Настройки приложения в app.config и реестре
  • Различные ресурсы и resx файлы

Исходный код этого приложения доступен на GitHub. Исходный источник (до переноса) доступен в NetFx\BeanTraderClient каталоге. Последнее перемещенное приложение находится в NetCore\BeanTraderClient директории. Бэкэнд-сервис, с которым должно соединяться приложение, доступен в BeanTraderServer папке.

Отказ

Помните, что этот образец приложения создан для демонстрации проблем перемещения на .NET Core и их решений. Он не предназначен для демонстрации лучших WPF возможностей. На самом деле, некоторые анти-паттерны были намеренно добавлены в приложение для воспроизведения некоторых проблем при перемещении.

Обзор процесса перемещения

Процесс перехода с .NET Framework на .NET Core состоит из четырех основных этапов.

1. Во-первых, полезно подготовиться к перемещению, разобраться в зависимостях проекта и перемещать проект в легко переносимом состоянии.

  1. Используйте такие инструменты, как .NET Portability Analyzer, для изучения .NET Framework зависимостей.
  2. Также стоит обновить NuGet ссылки для использования <PackageReference> формата и, возможно, придется обновить версии NuGet пакетов.

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

3. В-третьих, исходному коду могут потребоваться некоторые обновления, основанные на различных API, как в .NET Core, так и в .NET Core версиях необходимых NuGet пакетов. Это обычно самый продолжительный этап.

4. В-четвертых, не забудьте протестировать перенесенное приложение! Некоторые .NET Core/.NET Framework различия не проявляются до времени выполнения (хотя существуют Roslyn анализаторы кода, помогающие идентифицировать эти случаи).

Шаг 1: Подготовка

Образец клонирован и готов к работе? Супер, теперь можно начать!

Основная проблема при перемещение .NET Framework приложения на .NET Core заключается в том, что его зависимости в .NET Core могут работать по-разному (или вообще не работать!). Сейчас перемещение стало намного проще, чем раньше - многие NuGet пакеты теперь нацелены на .NET Standard, и, начиная с .NET Core 2.0, .NET Framework и .NET Core стали довольно похожими. Тем не менее, некоторые различия остаются (как в поддержке NuGet пакетов, так и в доступных .NET API).

Обновление NuGet ссылок к <PackageReference>

Старые .NET Framework проекты обычно перечисляют свои NuGet зависимости в packages.config файле. Однако новый формат файла проекта в SDK стиле по-разному ссылается на NuGet пакеты. Для ссылки на NuGet зависимости он использует <PackageReference> элементы в самом csproj файле (а не в отдельном файле конфигурации). К счастью, csproj файлы старого стиля также могут использовать современный синтаксис.

При перемещении есть два преимущества использования ссылок в <PackageReference> стиле:

  1. Это стиль NuGet ссылки, который потребуется для нового файла .NET Core проекта. Если Вы уже используете <PackageReference>, эти элементы файла проекта можно скопировать и вставить непосредственно в новый проект.
  2. В отличие от packages.config файла, элементы <PackageReference> ссылаются только на самые важные зависимости, от которых напрямую зависит Ваш проект. Все остальные переходные NuGet пакеты будут определены во время восстановления и записаны в автоматически сгенерированный obj\project.assets.json файл. Это значительно упрощает рассуждение о том, какие зависимости есть у Вашего проекта, что полезно при определении того, будут ли необходимые зависимости работать на .NET Core или нет.

Итак, первый шаг к перемещению Bean Trader образца - это подготовить его к использованию <PackageReference> NuGet ссылок. С Visual Studio это очень легко. Просто щелкните правой кнопкой мыши по packages.config файлу проекта в Visual Studio Solution Explorer и выберите «Перенести packages.config в PackageReference».

Появится диалоговое окно, показывающее вычисленные самые важные NuGet зависимости и спрашивающее, какие другие NuGet  пакеты должны быть перемещены к этому уровню. Ни один из этих других пакетов не должен быть высокого уровня для Bean Trader образца, поэтому Вы можете снять все эти флажки. Затем нажмите «ОК», и packages.config файл будет удален, а <PackageReference> элементы будут добавлены в файл проекта.

Ссылки в стиле <PackageReference> не хранят NuGet пакеты локально в папке «пакетов» (вместо этого они хранятся глобально, в качестве оптимизации), поэтому после перемещения Вам нужно будет отредактировать csproj файл и удалить <Analyzer> элементы, относящиеся к FxCop анализаторам, которые ранее были из .. \packages директории.

Просмотрите NuGet пакеты

Теперь, когда можно увидеть NuGet пакеты верхнего уровня, от которых зависит проект, есть возможность проверить, будут ли эти пакеты доступны в .NET Core или нет.

Вы можете узнать, поддерживается ли .NET Core пакет, взглянув на его зависимости от nuget.org. Сайт fuget.org, созданный сообществом, также отображает эту информацию в верхней информационной части страницы пакета.

При нацеливании на .NET Core 3 должны работать любые пакеты, нацеленные на .NET Core или .NET Standard (поскольку .NET Core реализует .NET Standard). Вы также можете использовать пакеты, нацеленные на .NET Framework, но это представляет некоторый риск. Разрешены зависимости от .NET Core к .NET Framework, поскольку .NET Core и .NET Framework достаточно похожи, поэтому такие зависимости часто работают без проблем. Однако, если пакет пытается использовать .NET API, которого нет в .NET Core, Вы столкнетесь с трудностями во время работы. По этой причине Вы должны ссылаться на .NET Framework пакеты только тогда, когда другие опции недоступны, и помнить, что это создаст нагрузку на тестирование.

В случае примера Bean Trader есть следующие NuGet  зависимости:

  • Castle.Windsor, версия 4.1.1. Этот пакет предназначен для .NET Standard 1.6, поэтому он будет работать на .NET Core.
  • Microsoft.CodeAnalysis.FxCopAnalyzers, версия 2.6.3. Это метапакет, поэтому неясно, какие платформы он поддерживает, но в документации указано, что его новейшая версия (2.9.2) будет работать как для .NET Framework, так и для .NET Core.
  • Nito.AsyncEx, версия 4.0.1. Этот пакет не предназначен для .NET Core, но более новая версия 5.0 сможет это сделать. Это часто происходит при миграции, потому что многие NuGet пакеты за последний год добавили поддержку .NET Standard, но более старые проекты будут использовать более старые версии этих пакетов. Если разница версий незначительна, ее можно легко обновить до более новой версии. Поскольку это серьезное изменение версии, Вы должны быть осторожны при обновлении, поскольку в пакете могут произойти критические изменения.
  • MahApps.Metro, версия 1.6.5. Этот пакет также не предназначен для .NET Core, но имеет более новую preview-версию (2.0-alpha).

Все NuGet зависимости из примера Bean Trader предназначены либо для .NET Standard/.NET Core, либо для их более новых версий, поэтому у Вас вряд ли возникнут какие-либо проблемы с блокировкой.

Если бы существовали пакеты, не предназначенные для .NET Core или .NET Standard, пришлось бы подумать о других альтернативах:

  • Есть ли другие похожие пакеты, которые можно использовать вместо этих? Иногда NuGet авторы публикуют отдельные .Core версии библиотек, специально предназначенные для .NET Core. Пакеты Enterprise Library - пример того, как сообщество публикует альтернативы с .NetCore расширением.
  • Если альтернатив нет, Вы можете продолжить использование пакетов, нацеленных на .NET Framework, имея в виду, что Вам потребуется тщательно их протестировать после запуска на .NET Core.

Обновите NuGet пакеты

Если у Вас есть такая возможность, обновите версии этих пакетов до тех, которые нацелены на .NET Core или .NET Standard на этом этапе, чтобы обнаружить и устранить любые критические изменения.

Если Вы не хотите вносить какие-либо существенные изменения в существующую версию .NET Framework приложения, подождите, пока у Вас не появится новый файл проекта для .NET Core. Тем не менее, предварительное обновление NuGet пакетов до версий, совместимых с .NET Core, упрощает процесс миграции, когда наступает время создания нового файла проекта, и уменьшает количество различий между .NET Framework и .NET Core. версиями приложения.

В случае примера Bean Trader все необходимые обновления могут быть легко выполнены (с помощью диспетчера NuGet пакетов в Visual Studio) с одним исключением: обновление с MahApps.Metro 1.6.5 до 2.0 выявляет серьезные изменения, связанные с API-интерфейсами для управления темами и акцентами.

В идеале приложение должно быть обновлено, чтобы использовать более новую версию пакета (так как оно, скорее всего, будет работать на .NET Core). Однако в некоторых случаях это может быть неосуществимо. В этом случае MahApps.Metro не будет обновляться, потому что этот туториал сосредоточен на переходе на .NET Core 3, а не на MahApps.Metro 2. Кроме того, это .NET Framework зависимость с низким уровнем риска, поскольку приложение Bean Trader выполняет только небольшую часть MahApps.Metro. Конечно, после завершения миграции потребуется тестирование, чтобы убедиться, что все работает.

После обновления NuGet пакетов до последних версий группа элементов <PackageReference> в файле проекта Bean Trader должна выглядеть следующим образом:

Анализ переносимости .NET Framework

Теперь рассмотрим зависимости .NET Framework API. Инструмент .NET Portability Analyzer полезен для понимания того, какие из .NET API, которые использует Ваш проект, доступны на других .NET платформах.

Этот инструмент поставляется в виде Visual Studio плагина, инструмента командной строки или в виде простого графического интерфейса пользователя, который упрощает его параметры и всегда сообщает о совместимости с .NET Core 3.

В предыдущем посте Оля Гавриш использовала графический интерфейс, поэтому в этом будет использоваться интерфейс командной строки. Необходимые шаги:

1. Загрузите API Portability Analyzer.

2. Убедитесь, что приложение .NET Framework для переноса собралось успешно.

3. Запустите API-порт с помощью командной строки, например:

  1. ApiPort.exe analyze -f <PathToBeanTraderBinaries> -r html -r excel -t ".NET Core"
  2. Аргумент -f указывает путь, содержащий двоичные файлы для анализа. Аргумент -r указывает, какой формат выходного файла Вам нужен. Будут полезны как HTML, так и Excel форматы. Аргумент -t указывает, с какой .NET платформой будет анализироваться использование API. В данном случае нужен .NET Core, поскольку именно эта платформа является целевой.  Так как версия не указана, по умолчанию для API Port используется последняя версия платформы (в данном случае - .NET Core 3.0).

Когда Вы откроете HTML-отчет, в первом разделе будут перечислены все проанализированные двоичные файлы и какой процент используемых им .NET API доступен на целевой платформе. Сам по себе этот процент не очень значимый. Что более полезно, так это увидеть конкретные API, которые отсутствуют. Для этого щелкните имя сборки или прокрутите вниз до отчетов по отдельным сборкам.

Вам нужно беспокоиться только о тех сборках, для которых у Вас есть исходный код. В отчете Bean Trader ApiPort перечислено много двоичных файлов, но большинство из них относится к NuGet пакетам. Например, Castle.Windsor показывает, что он зависит от некоторых System.Web API интерфейсов, отсутствующих в .NET Core. Это не проблема, потому что Castle.Windsor поддерживает .NET Core. Обычно NuGet пакеты имеют разные двоичные файлы для использования на разных  .NET платформах, поэтому независимо от того, использует ли .NET Framework версия Castle.Windsor System.Web API-интерфейсы или нет, это не имеет значения, если пакет также предназначен для .NET Standard или. NET Core.

В случае примера Bean Trader единственный двоичный файл, который нужно изучить - BeanTraderClient, и в отчете показано, что отсутствуют только два .NET API - System.ServiceModel.ClientBase<T>.Close и System.ServiceModel.ClientBase<T>.Open

Это вряд ли избавит от проблем, потому что WCF Client API (в основном) поддерживаются в .NET Core, поэтому для этих центральных API должны быть альтернативы. Фактически, глядя на System.ServiceModel .NET Core (используя https://apisof.net), можно увидеть, что в .NET Core есть асинхронные альтернативы.

Исходя из этого отчета и предыдущего анализа NuGet зависимостей, похоже, что не должно быть серьезных проблем при переносе образца Bean Trader в .NET Core. Следующий шаг для начала переноса.

Шаг 2: Перемещение файла проекта

Поскольку .NET Core использует новый формат файла проекта в SDK стиле, существующий csproj файл не будет работать. Нам понадобится новый файл проекта для .NET Core версии приложения Bean Trader. Если Вам не нужно было собирать .NET Framework версию приложения в будущем, Вы могли бы просто заменить существующий csproj файл. Но часто разработчики хотят создавать обе версии - особенно тогда, когда .NET Core 3 все еще находится в режиме предварительного просмотра.

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

 

  1. Вы можете использовать многоцелевой таргетинг (указав несколько <TargetFrameworks> целей), чтобы получить один файл проекта, который создаст .NET Core и .NET Framework версии решения. В будущем это, вероятно, будет лучшим вариантом. Однако, на данный момент, некоторые функции плохо работают с многоцелевым таргетингом. Поэтому сейчас рекомендуется иметь отдельные файлы проекта для версий приложений, ориентированных на .NET Core и .NET Framework.
  2. Вы можете поместить новый файл проекта в другую директорию. Это облегчит разделение сборки, но означает, что Вы не сможете использовать преимущества новой системы проектов, позволяющей автоматически добавлять C# и XAML файлы. Также необходимо будет добавить <Link> элементы для XAML ресурсов, чтобы они были встроены с правильными путями.
  3. Вы можете поместить новый файл проекта в ту же директорию, что и текущий файл проекта. Это позволяет избежать проблем, связанных с предыдущим параметром, но приведет к конфликту obj и bin папок для двух проектов. Если Вы одновременно открываете только один из проектов, это не будет проблемой. Но если они оба будут открыты одновременно, Вам нужно будет обновить проекты, чтобы использовать разные пути вывода и промежуточные пути вывода.

 

Лучший вариант - пункт 3 (чтобы файлы проекта работали бок о бок), поэтому этот подход будет использоваться в качестве примера.

Для создания нового файла проекта, обычно используется команда dotnet new wpf во временном каталоге, чтобы сгенерировать файл проекта, а затем скопировать / переименовать его в нужное место. Существует также созданный сообществом инструмент CsprojToVs2017, который может автоматизировать некоторые процессы миграции. Этот инструмент полезен, но все еще нуждается в улучшении, чтобы  все детали миграции были верны. Одна конкретная область, которую инструмент не обрабатывает до конца, - это миграция NuGet пакетов из packages.config файлов. Если инструмент запускается в файле проекта, который все еще использует файл packages.config для ссылки на NuGet пакеты, он автоматически мигрирует в <PackageReference> элементы, но добавит <PackageReference> элементы для всех пакетов, а не только для верхнего уровня. Однако если Вы уже перешли на <PackageReference> элементы с помощью Visual Studio, то этот инструмент может помочь с остальной частью конвертирования. Перенос вручную даст лучшие результаты, если у Вас только несколько проектов. Но если Вы портируете десятки или сотни файлов проекта, то такой инструмент, как CsprojToVs2017, может Вам помочь.

Так что, запустите dotnet new wpf во временном каталоге и переместите созданный csproj файл в BeanTraderClient папку и переименуйте его в BeanTraderClient.Core.csproj.

Поскольку новый формат файла проекта автоматически включает C#, resx и XAML файлы, которые он находит в своей директории, файл проекта уже почти готов! Чтобы завершить миграцию, одновременно откройте старые и новые файлы проекта и просмотрите старый, чтобы увидеть, нужно ли переносить какую-либо информацию, содержащуюся в нем. В этом случае следующие элементы должны быть скопированы в новый проект:

 

  • <RootNamespace>, <AssemblyName> и <ApplicationIcon> свойства должны быть скопированы.
  • Также нужно добавить <GenerateAssemblyInfo>false</GenerateAssemblyInfo> свойство в новый файл проекта, поскольку образец Bean Trader включает атрибуты уровня сборки в файле AssemblyInfo.cs (например, [AssemblyTitle]). По умолчанию новые проекты в SDK стиле автоматически генерируют эти атрибуты на основе свойств в csproj файле. Поскольку в этом случае это не нужно (автоматически сгенерированные атрибуты будут конфликтовать с теми что из AssemblyInfo.cs), Вам нужно отключить автоматически сгенерированные атрибуты с помощью <GenerateAssemblyInfo>.
  • Хотя resx файлы автоматически добавляются в качестве встроенных ресурсов, другие <Resource> элементы, например изображения, не добавляются. Итак, скопируйте <Resource> элементы для того, чтобы вставить изображения и значки файлов. Вы можете упростить png ссылки на одну строку, используя поддержку нового формата файла проекта для сокращения шаблонов: <Resource Include="**\*.png" />.
  • Аналогично, <None> элементы будут включены автоматически, но по умолчанию они не будут скопированы в директорию выхода. Поскольку проект Bean Trader включает в себя <None> элемент, который копируется в директорию выхода (с использованием PreserveNewest), необходимо обновить автоматически заполненный <None> элемент для этого файла, например:
  • Образец Bean Trader содержит XAML файл (Default.Accent.xaml) в качестве Содержимого (а не Страницы), поскольку темы и акценты, определенные в этом файле, загружаются из XAML файла во время выполнения, а не встраиваются в само приложение. Новая система проекта автоматически содержит этот файл в виде <Страницы>, разумеется, поскольку это XAML файл. Итак, нужно удалить как XAML файл, так и страницу (<Page Remove="**\Default.Accent.xaml" />) и добавить его в качестве содержимого:
  • Наконец, добавьте NuGet ссылки, скопировав <ItemGroup> со всеми <PackageReference> элементами. Если бы ранее NuGet пакеты не обновлялись до версий, совместимых с .NET Core, Вы могли бы сделать это сейчас, когда ссылки на пакеты находятся в специфичном для .NET Core проекте.

 

На этом этапе должна появиться возможность добавить новый проект в решение BeanTrader и открыть его в Visual Studio. Проект должен выглядеть правильно в Solution Explorer и dotnet restore BeanTraderClient.Core.csproj должен успешно восстановить пакеты (с двумя ожидаемыми предупреждениями, связанными с MahApps.Metro версией, которая используется для нацеливания на .NET Framework).

Это, вероятно, хороший переломный момент между первой и второй частями этого блог поста. Во втором посте будет рассказано о том, как приложение собирается и работает на .NET Core.

Источник



Exception: Stack empty.
Posted on 10. May 2019

Улучшенная диагностика в .NET Core 3.0

В .NET Core 3.0 добавлен набор инструментов, которые используют новые функции в .NET среде, что значительно улучшает диагностику и производительность.

Эти функции помогут Вам ответить на некоторые распространенные вопросы диагностики:

  1. Все ли в порядке с моим приложением?
  2. Почему возникает аномальное поведение в моем приложении?
  3. Почему мое приложение падает?

Все ли в порядке с моим приложением?

Часто приложения могут запускать утечку памяти и в конечном итоге это приводит к нехватки памяти. В других случаях определенные проблемные пути кода могут привести к скачку использования ЦПУ. Это лишь некоторые из проблем, которые Вы можете активно идентифицировать с помощью метрик.

Метрики

Метрики - это данные измерений за определенные промежутки времени. Данные метрик (или временных рядов) позволят Вам наблюдать за состоянием Вашей системы самым лучшим образом. В отличие от .NET Framework на  Windows, .NET Core не отслеживает производительность. Поэтому был добавлен новый способ генерирования метрик в .NET Core с помощью EventCounter API.

EventCounters намного лучше по сравнению с Windows счетчиками производительности, поскольку теперь они используются на всех ОС, где поддерживается .NET Core. Кроме того, в отличие от счетчиков производительности, они также могут использоваться в средах с низким уровнем привилегий (например, при xcopy развертывании). К сожалению, отсутствие такого инструмента, как Performance Monitor (perfmon), затрудняет использование этих метрик в режиме реального времени.

dotnet-counters

В .NET Core 3.0 Preview 5 есть новый инструмент командной строки для наблюдения за метриками, генерируемыми .NET Core Applications в режиме реального времени.

Вы можете установить этот .NET инструмент, выполнив следующую команду.

dotnet tool install --global dotnet-counters --version 1.0.3-preview5.19251.2

 

Для получения подробных инструкций о том, как использовать этот инструмент, перейдите на dotnet-counters readme. Для ознакомления с известными ограничениями dotnet-counters, перейдите на GitHub.

Почему возникает аномальное поведение в моем приложении?

В то время как метрики помогают идентифицировать возникновение аномального поведения, они предоставляют мало информации о том, что именно пошло не так. Чтобы ответить на вопрос, почему в приложении возникает аномальное поведение, Вам нужно собрать дополнительную информацию с помощью трассировок, что поможет определить проблемные места в коде.

Трассировка

Трассировки - это неизменные записи дискретных событий с отметкой времени. Трассировки содержат локальный контекст, который позволяет лучше определить сбой системы. Обычно .NET Framework (и такие фреймворки, как ASP.NET) генерировали диагностические трассировки о своих внутренних компонентах с помощью Event Tracing для Windows (ETW). В .NET Core эти трассировки были прописаны в ETW для Windows и LTTng для Linux.

dotnet-trace

В .NET Core 3.0 Preview 5 каждое .NET Core приложение открывает двойной канал с именем EventPipe (Unix сокет домен именованный pipe на Windows), через который можно отправлять события. На данный момент ведутся работы над протоколом контроллера, dotnet-trace реализует preview-версию этого протокола.

Вы можете установить этот .NET инструмент, выполнив следующую команду

dotnet tool install --global dotnet-trace--version 1.0.3-preview5.19251.2

 

В приведенном выше примере запускается dotnet trace с профилем по умолчанию, который включает аналитику событий ЦПУ и события .NET среды. 

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

В результате запуска dotnet trace Вы получаете .netperf файл. Этот файл содержит события времени выполнения и выборки ЦПУ стеков, которые можно визуализировать в perfview. Следующее обновление Visual Studio (16.1) также добавит поддержку для визуализации этих трассировок.

Если при записи трассировки Вы работаете на X или Linux, Вы можете преобразовать эти .netperf файлы в .speedscope.json файлы, которые можно визуализировать с помощью Speedscope.app.

Вы можете преобразовать уже существующую трассировку, выполнив следующую команду

dotnet trace convert <input-netperf-file>

Изображение ниже показывает диаграмму, визуализирующую трассировку, которую Вы только что зафиксировали в Speedscope.

Для получения подробных инструкций о том, как использовать этот инструмент, перейдите на dotnet-trace readme. Для ознакомления с известными ограничениями dotnet-trace, перейдите на GitHub.

Почему мое приложение падает?

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

Dump анализ

Dump - это запись состояния рабочей виртуальной памяти процесса, обычно сделанная при неожиданном завершении процесса. Dump диагностика ядра обычно используется для выявления причин сбоев приложения или непредвиденного поведения.

Обычно Вы полагались на операционную систему для получения dump анализа при сбое приложения (например, Windows Error Reporting) или использовали инструмент, такой как procdump, для доступа к dump при выполнении определенных критериев запуска.

До сих пор проблема с захватом dump анализа с помощью .NET на Linux заключалась в том, что захват дампов с помощью gcore или debugger приводил к очень большим сложностям, поскольку существующие инструменты не знали, какие страницы виртуальной памяти обрезать в .NET Core процессе.

Кроме того, было сложно проанализировать эти dump даже после того, как Вы их собрали, поскольку требовалось использовать debugger и настроить его для sos загрузки, debugger расширения для .NET.

dotnet-dump

В 3.0.0-preview5 добавлен новый инструмент, который собирает и анализирует dump процессы как на Windows, так и на Linux. 

dotnet-dump все еще находится в активной разработке, и в таблице ниже показано, какие функции и на каких ОС поддерживаются на данный момент.

  Windows OS X Linux
Collect
✅
❌
✅
Analyze
❌
❌
✅


Вы можете установить этот .NET инструмент, выполнив следующую команду

dotnet tool install --global dotnet-dump --version 1.0.3-preview5.19251.2

После того, как Вы установили dotnet dump, Вы можете записать dump процесс, выполнив следующую команду

sudo $HOME/.dotnet/tools/dotnet-dump collect -p <pid>

На Linux полученный dump можно проанализировать, загрузив его с помощью следующей команды

dotnet dump analyze <dump-name>

 

Для получения подробных инструкций о том, как использовать этот инструмент, перейдите на dotnet-dump readme. Для ознакомления с известными ограничениями dotnet-dump, перейдите на GitHub.

В заключение

 

Не забудьте опробовать новые инструменты диагностики в .NET Core 3.0. Пожалуйста, оставьте Ваш отзыв, напишите в комментариях ниже  или на GitHub. Ваша оценка будет учитываться при будущих обновлениях.

 

Источник



Exception: Stack empty.
Posted on 12. March 2019

Как переносить настольные приложения на .NET Core 3.0

В этой статье будет рассмотрен перенос настольного приложения с .NET Framework на .NET Core. В качестве примера возьмем WinForms приложение. Шаги для WPF приложения схожи, различия рассмотрим по ходу. Также увидим как использовать WinForms designer в Visual Studio, хотя он находится в стадии разработки и еще не доступен для .NET Core проектов.

О примере

Для этого поста будет использовано игровое Memory-style board приложение. Оно состоит из WinForms UI (MatchingGame.exe) и библиотеки классов с игровой логикой (MatchingGame.Logic.dll), которые предназначены для .NET Framework 4.5. Здесь можно скачать образец. Итак, рассмотрим перенос проекта приложения на .NET Core 3.0, а также библиотеки классов на .NET Standard 2.0. Использование .NET Standard вместо .NET Core позволяет повторно использовать игровую логику для размещения приложения на других платформах, таких как iOS, Android или в вебе.

 

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

Пошаговый процесс

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

Прежде чем переносить приложение на .NET Core 3.0, подготовите следующее:

  1. Установите .NET Core 3 и Visual Studio 2019 Preview версию (Visual Studio 2017 поддерживает версии только до .NET Core 2.2).
  2. Начните с рабочего проекта. Убедитесь, что проект беспроблемно открывается, собирается и запускается.
  3. Обновите NuGet пакеты. Всегда рекомендуется использовать последние версии NuGet пакетов перед любым переносом. Если Ваше приложение ссылается на какие-либо NuGet пакеты, обновите их до последней версии. Убедитесь, что Ваше приложение успешно собрано. Если NuGet выдает ошибки, понизьте версию и найдите последнюю, которая не нарушает Ваш код.
  4. Запустите .NET Portability Analyzer, чтобы определить, существуют ли какие-либо API, от которых зависит Ваше приложение, и которые отсутствуют в .NET Core. Если таковые имеются, Вам необходимо провести рефакторинг своего кода, чтобы избежать зависимостей от API, не поддерживаемых в .NET Core. Иногда можно найти альтернативный API, который обеспечивает необходимую функциональность.
  5. Замените packages.config на PackageReference. Если используются NuGet пакеты, то нужно добавить те же NuGet пакеты в новый .NET Core проект. .NET Core проекты поддерживают только PackageReference для добавления NuGet пакетов. Чтобы переместить ссылки NuGet из packages.config в файл проекта, в обозревателе решений необходимо щелкнуть правой кнопкой на packages.config -> Migrate packages.config в PackageReference… Более детально об этом типе переноса можно ознакомиться по ссылке Migrate from packages.config to PackageReference.

 

Портирование основного проекта

Создание нового проекта
  • Создайте новое приложение того же типа (Console, WinForms, WPF, Class Library), что и приложение, которое нужно перенести, для .NET Core 3. На данный момент были сделаны демонстрационные Visual Studio шаблоны для десктопных проектов, которые находились в стадии разработки, поэтому использовалась консоль.
dotnet new winforms -o \MatchingGame.Core\
  • Скопируйте в файле проекта все внешние ссылки из старого проекта, например:
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
  • Начните сборку. На этом этапе, если пакеты, на которые Вы ссылаетесь, поддерживают только .NET Framework, Вы получите NuGet предупреждение. Если Вы не обновились к последней версии NuGet пакета на шаге 3, попробуйте определить, доступна ли последняя версия, поддерживающая .NET Core (.NET Standard), и повторите обновление. Если более новой версии нет, то .NET Framework пакеты все еще можно использовать, но можно получить ошибки времени выполнения, если эти пакеты имеют зависимости от API, не поддерживаемых в .NET Core. В таком случае рекомендуется сообщить автору NuGet пакета, что Вас заинтересовало бы обновление пакета до .NET Standard. Сделать это можно через контактную форму в NuGet галерее.
Быстрый способ (заменить существующий файл проекта)

Итак, быстрый способ переноса. Убедитесь, что у Вас есть копия текущего .csproj файла, возможно, Вам придется использовать его в будущем. Замените текущий .csproj файл .csproj файлом из проекта, созданного ранее, и добавьте вверху <PropertyGroup> следующее:

<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
Соберите приложение. Если ошибок не возникло, то перенос проекта на .NET Core 3 прошел успешно. Для перемещения зависимого (UI) проекта рекомендуется ознакомиться с разделом «Перенос пользовательского интерфейса»), чтобы узнать, как использовать Designer, ознакомьтесь с разделом «Использование WinForms Designer для проектов .NET Core».

Медленный путь (управляемый перенос)

Если система выдает ошибки, то нужно внести дополнительные корректировки. Здесь предоставлена информация о внесении изменений в код с возможными исправлениями для каждого вопроса. Шаги ниже также помогут лучше понять процесс переноса, поэтому, если быстрый способ помог, но Вам интересно узнать «почему и как», продолжайте читать.
  • Перейдите в.csproj файл в SDK-style. Чтобы переместить приложение в .NET Core, сначала нужно изменить файл проекта в SDK формате, поскольку старый формат не поддерживает .NET Core. Кроме того, SDK-style формат намного проще и с ним легче работать. Убедитесь, что копия текущего .csproj файла создана. Замените содержимое .csproj файла следующим. Для WinForms приложения:
  
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net472</TargetFramework>
    <UseWindowsForms>true</UseWindowsForms>
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
  </PropertyGroup>
</Project></pre>
Для WPF приложения:

  
    <Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net472</TargetFramework>
    <UseWPF>true</UseWPF>
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
  </PropertyGroup>
</Project>
Обратите внимание, что значение <GenerateAssemblyInfo> было установлено как false. В проектах нового стиля AssemblyInfo.cs генерируется автоматически по умолчанию. Так что, если проект уже содержит файл AssemblyInfo.cs файл (а он содержит), то необходимо отключить авто-генерацию или удалить файл.

Теперь скопируйте и вставьте все ссылки из старой версии .csproj файла в новую. Например:

Ссылка на NuGet пакет
 
<PackageReference Include="Microsoft.Windows.Compatibility" Version="2.0.1" />
Ссылка на проект
 
<ProjectReference Include="..\MatchingGame.Core\MatchingGame.Core.csproj" />

Проект должен успешно сформироваться, так как это просто новый способ написать то же самое. Если возникли какие-либо ошибки, то перепроверьте сделанные шаги.

Существует также сторонний инструмент CsprojToVs2017, который может выполнить преобразование. Но после его использования все равно может понадобиться удалить некоторые ссылки вручную, например:
<Reference Include="System.Data.DataSetExtensions"></Reference>
<Reference Include="Microsoft.CSharp"></Reference>
<Reference Include="System.Net.Http"></Reference>

  • Перейдите от .NET Framework к .NET Standard или .NET Core. После успешного преобразования библиотеки в SDK формат, ее можно перенастроить. В данном случае, необходимо, чтобы библиотека классов предназначалась для .NET Standard вместо .NET Core. Таким образом, она будет доступна из любой .NET реализации, если нужно отправить игру на другие платформы (например, iOS, Android или Web Assembly). Для этого замените данную строку
<TargetFramework>net472</TargetFramework>
на следующую

<TargetFramework>netstandard2.0</TargetFramework>
Создайте Ваше приложение. Если Вы используете API, которые не включены в .NET Standard, то могут возникнуть ошибки. Если ошибок нет, то следующие два шага можно пропустить.

  • Добавьте Windows Compatibility Pack для совместимости, если необходимо.Некоторые API, которые не включены в .NET Standard, доступны в Windows пакете совместимости. Если на предыдущем шаге были получены ошибки, то можно проверить, поможет ли Windows пакет совместимости. В рассматриваемом приложении была получена следующая ошибка «Имя реестра не существует в текущем контексте», поэтому в проект был добавлен Microsoft.Windows.Compatibility NuGet пакет. После установки ошибка исчезла.
  • Установите API Analyzer. API Analyzer, доступный в виде NuGet пакета Microsoft.DotNet.Analyzers.Compatibility, предупредит об использовании устаревших API или API, которые не поддерживаются на всех платформах (Windows, Linux, macOS). Если был добавлен пакет совместимости, то рекомендуется добавить и API Analyzer для отслеживания случаев использования API, которые не будут работать на всех платформах. На этом рассмотрение процесса переноса библиотеки классов на .NET Standard заканчивается. Если у Вас есть несколько проектов, которые ссылаются друг на друга, переносите их «снизу вверх», начиная с проекта, который не зависит от других. В данном примере также есть WinForms MatchingGame.exe проект, поэтому теперь необходимо выполнить аналогичные шаги для его переноса в .NET Core.
Перенос пользовательского интерфейса
  • Добавьте .NET Core UI проект. Внедрите в решение новый .NET Core 3.0 UI проект. На данный момент Visual Studio шаблоны для настольных приложений находятся в стадии разработки, поэтому можно просто использовать dotnet CLI.
dotnet new winforms -o \MatchingGame.Core\
Для WPF проектов можно использовать следующее:

dotnet new wpf -o \MatchingGame.Core\
После того, как был создан новый WinForms .NET Core проект, его необходимо добавить в Ваше решение.
  • Свяжите проекты. Сначала удалите все файлы из нового проекта (прямо сейчас он содержит общий Hello World код). Затем свяжите все файлы из существующего .NET Framework UI проекта с .NET Core 3.0 UI проектом, добавив в .csprojfile файл следующую команду.
    
<ItemGroup>
    <Compile Include="..\\**\*.cs" />
    <EmbeddedResource Include="..\\**\*.resx" />
</ItemGroup>
Если у Вас WPF приложение, также необходимо включить .xaml файлы:

  
<ItemGroup>
  <ApplicationDefinition Include="..\WpfApp1\App.xaml" Link="App.xaml">
    <Generator>MSBuild:Compile</Generator>
</ApplicationDefinition>
<Compile Include="..\WpfApp1\App.xaml.cs" Link="App.xaml.cs"></Compile>
</ItemGroup>

<ItemGroup>
  <Page Include="..\WpfApp1\MainWindow.xaml" Link="MainWindow.xaml">
    <Generator>MSBuild:Compile</Generator>
  </Page>
  <Compile Include="..\WpfApp1\MainWindow.xaml.cs" Link="MainWindow.xaml.cs" />
</ItemGroup>
  • Совместите пространство имен по умолчанию и имя сборки. Поскольку Вы ссылаетесь на файлы, созданные дизайнером (например, Resources.Designer.cs), то нужно убедиться, что версия Вашего .NET Core приложения использует то же пространство имен и то же имя сборки. Скопируйте следующие параметры из Вашего .NET Framework проекта:
<PropertyGroup>
    <RootNamespace><!-- (Your default namespace) --></RootNamespace>
    <AssemblyName><!-- (Your assembly name) --></AssemblyName>
</PropertyGroup>
  • Отключите AssemblyInfo.cs файл. Как было отмечено ранее, в проектах нового стиля AssemblyInfo.cs генерируется автоматически по умолчанию. В то же время AssemblyInfo.cs файл из старого WinForms проекта будет скопирован и в новый проект, так как все ** \ *.cs файлы были связаны на предыдущем шаге. Это приведет к дублированию AssemblyInfo.cs. Чтобы избежать этого в файле MatchingGame.Core проекта, для GenerateAssemblyInfo было установлено значение false.
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
  • Запустите новый проект. Установите новый .NET Core проект в качестве StartUp проекта и запустите его. Убедитесь, что все работает.
  • Скопируйте или оставьте ссылку. Теперь вместо связывания файлов можно скопировать их из старого .NET Framework UI проекта в новый .NET Core 3.0 UI проект. После этого предыдущий можно удалить.
Использование WinForms Designer для проектов .NET Core

Как было упомянуто выше, WinForms Designer для .NET Core проектов еще не доступен в Visual Studio. Однако есть два способа обойти данный вопрос: 

  1. Сохраните файлы связанными (просто не выполните предыдущий шаг) и скопируйте их, когда будет доступна designer поддержка. Таким образом, можно изменить файлы в старом .NET Framework WinForms проекте, используя designer. И изменения будут автоматически отражены в новом .NET Core WinForms проекте, поскольку они связаны между собой.
  2. Храните два файла проекта в той же директории, где и WinForms проект: старый .csproj файл из существующего .NET Framework проекта и новый .csproj файл в SDK-style нового .NET Core WinForms проекта. Нужно выгрузить и перезапустить проект с соответствующим файлом проекта в зависимости от того, хотите ли Вы использовать designer или нет.
Подведение итогов

В этой статье было показано, как перенести десктопное приложение, содержащее несколько проектов, из .NET Framework на NET Core. Обычно недостаточно просто перенастроить свои проекты на .NET Core. Также были описаны потенциальные проблемы, с которыми Вы можете столкнуться, и способы их решения. Кроме того, было рассмотрено, как можно использовать WinForms designer для портированных приложений, пока он еще не доступен для .NET Core проектов.



Exception: Stack empty.