Net core и net framework объединение

Обновлено: 07.08.2024

Пример 1

Для начала создадим и запустим консольное приложение Hello World (я буду использовать PowerShell для Windows, но в Bash для macOS или Linux все делается аналогично).

Команда dotnet new делает то же самое, что элемент меню File – New Project в Visual Studio. С её помощью можно создавать проекты различных типов. Используйте команду dotnet new , чтобы вывести список предустановленных шаблонов.

Давайте переместим часть логики в библиотеку классов. Для этого в дополнение к проекту hello создадим проект библиотеки классов.

Переименуем файл Class1.cs в HelloWorld.cs .

Чтобы использовать класс HelloWorld , нужно добавить в приложение hello ссылку на библиотеку, в которой содержится логика. Для этого можно изменить файл проекта или воспользоваться командой dotnet add reference .

Теперь изменим файл Program.cs так, чтобы в нем использовался класс HelloWorld .

Обновление файла Program.cs для дальнейшего использования класса HelloWorld:

Чтобы собрать и запустить приложение, введите команду dotnet run .

В командной строке также можно создавать тесты. Этот CLI поддерживает MSTest , а также популярную платформу xUnit . Давайте для примера воспользуемся xUnit.

Чтобы добавить тест, измените содержимое файла UnitTest1.cs , как показано ниже.

Добавление теста в файл UnitTest1.cs:

Теперь можно запустить тесты с помощью команды dotnet test .

Пример 2

Чтобы запустить тестовый веб-сервер, вновь введите команду dotnet run .

Откройте в браузере URL-адрес, который был выведен в консоли (это должен быть адрес localhost:5000).

Сейчас структура вашего проекта должна соответствовать вот такой структуре.

Структура созданного проекта:

Чтобы упростить редактирование файлов в Visual Studio, создадим файл решения *.SIN и добавим в него все проекты.

BCL — это набор базовых API, не зависящих от инфраструктур пользовательского интерфейса и моделей приложений. В него входят простые типы, файловый ввод-вывод, сетевые API, API сериализации, XML и другое.

Пример 3

Сравним его с файлом проекта консольного приложения hello.

Пример 4

Эта библиотека поддерживает дополнительные типы коллекций, которых нет в BCL. Один из них — тип Bag , не гарантирующий какого-либо порядка элементов. Изменим наше приложение hello так, чтобы в нем использовался этот тип.

Пример приложения с использованием PowerCollections:

Если вы запустите программу, то увидите следующее:

Компилятор выкинул warning но программа отработала!

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

Заключение

net framework to net core

Что имеем

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

Для того, чтобы добиться переносимости кода между различными средами исполнения (Framework и Core), нам на помощью приходит NetStandard (а конкретнее — netstandard2.0).

Ещё нужно быть готовым к тому, что часть технологий частично или полностью отсутствует в NetCore, а конкретно:

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

Детали переноса компонентов, служб, подсистем

Директивы препроцессора и условная компиляция

Примеры условных директив, которые приходилось применять на проекте:

Как вы заметили, специально не применялись проверки на конкретные версии runtime'ов для упрощения кода.

Target'ы в *.csproj проектах выглядят так:

→ Больше про Кроссплатформенное нацеливание

Реализация заглушек API

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

Например, в наших контрактах часто используется WCFный атрибут TransactionFlowAttribute , но он будет использоваться, но интерфейсы, на которые он навешивается используется повсеместно, поэтому делаем так:

Заворачиваем всё в NuGet пакеты

Для возможности подключения кода на разных рантаймах рекомендую заворачивать ваши сборки в NuGet пакеты, так что будет возможность иметь сразу несколько реализаций одновременно для NetFramework and NetCore.

https://docs.microsoft.com/ru-ru/dotnet/standard/library-guidance/media/cross-platform-targeting/nuget-package-multiple-assemblies.jpg

Инфраструктурная часть

К инфраструктурной части приложения относится:

  • Хостинг приложения (Реализация служб)
  • Логирование
  • Обработка ошибок
  • Конфигурация
  • Загрузочная часть (Bootstrapper)
  • Мониторинг

Конфигурация приложений

Конфигурация классических приложений Net Framework основывается на файлах app.config, и web.config, которые представляют из себя XML файлы и API работы с ними: System.Configuration и класс System.Configuration.ConfigurationManager. Например, часто приходится считывать данные из AppSettings и гораздо реже делать свои классы конфигурации в ConfigurationSection.

В NetCore появилось новое API, которое позволяет работать с конфигурацией в различных форматах (JSON, INI, XML) и использовать различные источники (Файлы, Командная строка, Переменные окружения и т. д.)

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

Кстати, в StackOverflow имеется куча вопросов как организовать конфигурацию

Если всё-таки нужно использовать старую реализацию, то имеется NuGet пакет System.Configuration.ConfigurationManager.

NetCore реализация конфигурации более интуитивная и простая. Здесь вы работаете с конфигурацией по конкретному пути в конфигурационном файле, либо как с объектом (и не нужно описывать сложных ConfigurationSection )

Логирование

В старом проекте применялось логирование в EventLog с использованием API из System.Diagnostics , но а так же была абстракция в виде интерфейса ILogger , которая позволяла логировать с различными уровнями messageLevel (Debug, Info, Warning, Error) и указанием категорий. В более новых проектах уже применялся NLog c той же самой абстракцией ILogger .

В NetCore появилось новое универсальное API: Microsoft.Extensions.Logging, которое предоставляет интерфейс ILogger<T> .

Мы же продолжили использовать нашу абстракцию ILogger , потому что она везде, но конкретная реализация уже использует Microsoft.Extensions.Logging.ILogger<T> , а также она легко позволяет подключить и сконфигурировать кучу существующих логеров, например: NLog, log4Net, Serilog и т.д.

Внедрение зависимостей и инверсия управления

В наших проектах использовались IoC-контейнеры Unity, а в более новых — AutoFac, либо вовсе отсутствовали.

В NetCore добавлена абстракция Microsoft.Extensions.DependencyInjection с использованием класса ServiceCollection , которая позволяет регистрировать типы с уровнями:

Также имеется класс IServiceProvider, который обеспечивающий получение нужной регистрации.

  • Всегда используйте внедрение зависимостей через конструктор, затем методы или свойства. Если необходимо что-то конструировать в конкретном методе, то можете внедрить какую-нибудь фабрику и создавать что-либо вызывая её методы, саму фабрику регистрируем отдельно и поближе к конфигурации
  • Не пробрасывать контекст IoC-контейнера в код (это заставило нас попотеть, чтобы вынести код из классов)
  • Сосредоточьте регистрацию в одном месте

Избавляемся от Global Assembly Cache

Очень давно на проекте было принято решение использовать Global Assembly Cache, чтобы приложения не искали сборки и было централизованное место где они лежат.

Net Core не умеет в GAC, поэтому было принято решение написать кастомный AssemblyResolver, который искал бы в заданной директории используя конфигурацию.

Модели приложений

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

Принципиальных изменений в консольных приложениях нет, кроме того что нужно использовать новое API конфигурации, логгирования.

Windows Forms

Начиная с версии NetCore 3.0 появилась возможность запускать приложения Windows Forms, но после перехода на версию Net Core 3.1 часть legacy контроллов было удалено, поэтому
придётся немного переписать приложения.

Вот список контроллов, которые были "выпилены":

  • DataGrid и связанные с ним типы. Можно заменить на DataGridView;
  • ToolBar. Заменяем на ToolStrip;
  • MainMenu. Заменяем на MenuStrip;
  • ContextMenu. Заменяем на ContextMenuStrip.

Более подробно про изменения можно почитать Критические изменения в Windows Forms.

На первых этапах существования Windows Forms для NetCore 3.0 отсутствовал дизайнер форм для Visual Studio 2019, поэтому приходилось рисовать GUI в Net Framework, а потом переключаться на NetCore 3.0, но более поздних редакция появилась такая возможность.

Перенос будет чуть сложнее чем Windows Form приложения, но всё-равно всё происходит достаточно безболезненно.

Первое большое изменение — убран бутрстраппер Global.asax и заменён на класс Startup .

ASPNET ASMX переносим на AspNetCore WebAPI

На каждый asmx сервис создаём контроллер WebAPI и на каждый WebMethod создаём
Action POST метод и переносим соответствующий код с реализацией из asmx сервиса. Недостаток заключается в том, что мы полностью отходим от SOAP модели и вам также придётся переписывать клиентов. Если хотите, то можете оформить в виде Rest-служб.

Другой вариант — придётся использовать сторонние библиотеки, которые могут в SOAP , например: SoapCore.

Ещё один вариант — JSON-RPC, имеется куча различных библиотек под NetCore, все они хорошо внедряются в AspNet Core через Middleware.

ASPNET WebApi переносим на AspNetCore WebAPI

Достаточно простая задача, потому что идеология простоя: есть контроллеры и экшны.

шаги почти аналогичные с переносом MVC:

  • Global.asax и заменяем на класс Startup
  • Настраиваем авторизация и аутентификацию
  • Настраиваем Logger, Exception Handler
  • Портируем фильтры и т.д.

ASPNET Web Forms переносим на Blazor

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

Почему было решено портировать Web Forms на Blazor:

Для переноса было написано 2 утилиты:

В связи с тем, что у нас интерфейсы достаточно однотипные и простые, нам достаточно легко удалось портировать ASPNET Web Forms приложения.

Избавляемся от WCF

В NetCore есть частичная реализация WCF Client API:

Так как серверная сторона WCF полностью отсутствует в Net Core, то есть несколько вариантов:

  • Портируем как AspNetCore WebAPI
  • Портируем как AspNetCore gRPC
  • Используем стороннюю библиотеку CoreWCF с многими ограничениям
  • Портируем как AspNetCore + JSON-RPC

Другой вариант — AspNetCore gRPC: Перенос службы WCF "запрос — ответ" в gRPC унарный RPC

Пример WCF службы:

Пример gRPC контракта в protobuf формате:

Какой вариант реализации — решать вам, но я предпочитаю следующее:

  • Все внешние службы реализовать в виде WebAPI в стиле REST, либо JSON-RPC
  • Внутренние службы взаимодействуют по gRPC

Избавляемся от Workflow Foundation

Службы на Workflow Foundation полностью отсутствуют (в Microsoft, видимо, поняли что графическое представление службы никому не удобно и проще всё писать кодом), поэтому у вас есть такие варианты:

Лично мы решили просто избавиться от Workflow Foundation, он нам всегда доставлял неудобства и сделали старым добрым кодом. А что же может быть лучше старого доброго кода?

Подводим итоги

Первое время я испытывал эйфорию создавая объекты, классы. Еще ничего не знал о настоящем ООП. Позже пришли абстрактные классы и интерфейсы. К паттернам я испытывал отдельную любовь, красота с которой решаются проблемы проектирования завораживала. И да, много времени уходило на проектирование любого сложного участва программы. Зачастую паттерны были использованы ради паттернов. Делал маленькие проекты, рос, делал средние и ближе к 13 году уже большие сайты с отдельным бекендом, службами, базами. Почувствовал мощь платформы.

Средние века

Что еще было в 2010-2016 годах

Расписание студента

Я познакомился с Windows Phone уже версии 8.0. Появился магазин приложений. Он был пустой, был шанс быстро выбраться в топ. Было сделано 2 приложения. Это курс валют и простая казуальная игра Точки. Курс валют брал валюты с ЦБ РФ, установок было порядка 10к. Оба приложения выбрались в топ. Но, точки получили почти 150к установок за неделю. Я никак не монетизировал приложения, было интересно попробовать платформу и магазин приложений. В то время у меня уже был опыт разработки для мобильных устройств на iOS и опыт работы с iTunesConnect (сейчас который AppStoreConnect). Не без костылей, но приложения завелись. На Windows Phone модерация была примерно неделю, что было очень странно для компании, у которой нет ничего для удержания разработчиков. Даже у Apple модерация была в среднем 3-5 дней. Это потом Microsoft сделали модерацию приложений за сутки, но возможно было уже поздно.

Что сделали Microsoft с Windows Phone и где он сейчас? Обидно.

Курсы валют

После выхода Windows 8 и Windows 8.1 и сравнивая Windows Phone 8 и Windows Phone 8.1 оказалось, что это совершенно разные платформы. Как раз появилась возможность сделать “одно” приложение для обоих магазинов. Кстати, сами магазины приложения были совершенно разными и было видно, что их делали разыне команды, разные требования, интерфейс и вообще все. Я попробовал сделать приложение для обоих магазинов. Это было Судоку. Опубликова билды на 4pda, на хабре, и описал по горящим следам впечатления:

Сильно раздражало, что Microsoft пропагандирует, что это одна платформа и что в Windows 10 будет одна кодовая база. А на самом деле нет. Я сделал очень простое приложение судоку, а на деле получил информацию, что это абсолютно разные платформы. Да, классы называются похоже. Но локалазация в Windows Phone делается одним способом, в Windows Store другим, нельзя переиспользовать строки (локализацию пришлось копипастить). Layout делается для каждой платформы свой. Да, Xaml это отлично, но плохо, что верстка разная. Внутри было 2 проекта для Windows Store и Windows Phone.

Забегая вперед, Microsoft обещали сделать все хорошо в Windows 10. Придумали UWP (Universal Windows Platform). Завелось? Технологии порождаются с бешенной скоростью, а вот качество этих технологий распыляется. Вот список технологий, ключевых слов, за которыми Microsoft пророчили будущее:

Есть такие порталы как channel9 и user voice. Используются ли они для принятия решений? Не думаю. Сама IDE без сторонних решений не юзабельна. На одной из конференций Microsoft сказали, что гордятся тем, что для их продукта создаются сторонние решения, что разработчикам нравится делать продукты для Visual Studio. Это потому, что без них это жутко тормозной редактор кода. А новый, сверхскоростной редактор кода на javascript VS Code? Серьезно?

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

Я всегда был сторонником идеи, что и на Windows можно сделать все то же самое что и на linux. Профилирование приложений, статистика, память и прочее. Но, то, что на ubuntu делается просто (Elastic Kibana Logstash или Prometheus), на Windows боль. У Microsoft на все потребности пытается сделать что-то свое, а не использовать уже готовое, годами отработанное решение.

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

Я получаю огромное удовольствие от разработки, деплоя, поддержки всего на Python. Очень трудно все с нуля делать на Python, было много вопросов по самым простым процедурам. Например запись в файл и прочее. Но лаконичность, количество кода, стабильность. И самое главное - сообщество и экосистема!

Шаг 1. Запуск Portability Analyzer

Запускаем Portability Analyzer и указываем расположение исходного кода проекта:

Portability Analyzer

Portability Analyzer

После этого откроется файл Excel с отчётом по проверке. У меня этот файл выглядел следующим образом:

Portability Summary

Лист Portability Summary

Шаг 2. Миграция .csproj в SDK-стиле


А вот так будет выглядеть контекстное меню проекта без пункта:







Откроется XML-файл примерно такого содержания:


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

У меня такой блок оказался всего один, поэтом итоговый файл *.cproj стал выглядеть вот так:


Помогло удаление файла AssemblyInfo.cs


После этого проект запустился, работоспособность не нарушилась. Однако встретилась другая проблема.


Теперь необходимо добавить в проект пространство имен:

И можно пользоваться классами Point и Rect :

Читайте также: