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

  • Данный пост — простой случай. Он ориентирован на простые инструкции и небольшие приложения и рассматривает самый простой способ переноса приложения на .NET Core.
  • Позднее мы опубликуем еще один пост для более сложных случаев. В нем основное внимание будет уделено нетривиальным приложениям, таким как WPF-приложение с зависимостями от WCF и сторонних UI-пакетов.

Если вы предпочитаете смотреть видео, а не читать, то вот видео, где я делаю все, что описано ниже.


Шаг 0 – Предварительные условия


Для переноса десктопных приложений на Core понадобятся .NET Core 3 и Visual Studio 2019.

Шаг 1 – Запустите Portability Analyzer


Перед переносом следует проверить насколько совместимо ваше приложение с .NET Core. Для этого загрузите и запустите .NET Portability Analyzer.

  • На первой вкладке, Portability Summary, если в столбце .NET Core все значения стоят на 100% (все выделено зеленым), ваш код полностью совместим, и вы можете перейти к Шагу 2.
  • Если у вас есть значения менее 100%, сначала посмотрите на все сборки, которые не являются частью вашего приложения. Для них нужно проверить, предоставляют ли их авторы версии для .NET Core или .NET Standard.
  • Теперь посмотрите на другую часть сборок, которая поступает из вашего кода. Если в Portability Report не указано ни одной сборки, перейдите к Шагу 2. Как только вы это сделаете, откройте вкладку Details, отфильтруйте таблицу, кликнув столбец Assembly и сосредоточьтесь только на тех, которые связаны с вашим приложением. Просмотрите список и рефакторинг кода, чтобы прекратить использование API или заменить использование API с альтернативами .NET Core.

image

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


В Solution Explorer кликните правой кнопкой мыши свой проект (не решение!). Вы видите Edit Project File? Если да, то вы уже используете файл проекта в стиле SDK, поэтому вам следует перейти к Шагу 3. Если нет, сделайте следующее:

  • Проверьте в Solution Explorer, содержит ли проект файл packages.config. Если его нет, то никаких действий не требуется, однако если он есть, кликните правой кнопкой мыши packages.config и выберите Migrate packages.config to PackageReference. Затем нажмите OK.
  • Откройте файл проекта, кликнув правой кнопкой мыши по проекту и выбрав Unload Project. Затем кликните правой кнопкой мыши проект и выберите Edit <имя вашего проекта>.csproj.
  • Скопируйте куда-нибудь содержимое файла проекта, например, в Блокнот, чтобы позже производить в нем поиск.
  • Удалите все из файла проекта, открытого в Visual Studio (я знаю, это звучит агрессивно, но мы добавим только необходимый контент из копии, которую мы только что сделали в несколько шагов). Вместо только что удаленного текста вставьте следующий код.

    Для приложения на WinForms:

    <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net472</TargetFramework>
        <UseWindowsForms>true</UseWindowsForms>
        <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
      </PropertyGroup>
    </Project>

    Для приложения на WPF:

    <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net472</TargetFramework>
        <UseWPF>true</UseWPF>
        <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
      </PropertyGroup>
    </Project>
  • Найдите в Блокноте PackageReference. Если вы ничего не нашли, двигайтесь дальше. Если вы нашли PackageReference, скопируйте весь ItemGroup, содержащий PackageReference, в файл проекта, открытого в Visual Studio, прямо под строками, вставленными на шаге выше. Сделайте это для каждого элемента PackageReference, который вы нашли. Скопированный блок должен выглядеть так:

    <ItemGroup>
        <PackageReference Include="NUnit">
          <Version>3.11.0</Version>
        </PackageReference>
    </ItemGroup>
  • Теперь сделайте то же самое, что и выше, для ProjectReference. Если вы ничего не нашли, двигайтесь дальше. Если вы нашли какие-либо элементы ProjectReference, они будут выглядеть так:

    <ItemGroup>
      <ProjectReference Include="..\WindowsFormsApp1\WindowsFormsApp1.csproj">
        <Project>{7bce0d50-17fe-4fda-b6b7-e7960aed8ac2}</Project>
        <Name>WindowsFormsApp1</Name>
      </ProjectReference>
    </ItemGroup>
  • Вы можете удалить строки со свойствами Project и Name, так как они не нужны в новом стиле файла проекта. Так что для каждого ProjectReference, что вы нашли (если есть), копируйте только ItemGroup и ProjectReference.

    <ItemGroup>
      <ProjectReference Include="..\WindowsFormsApp1\WindowsFormsApp1.csproj" />
    </ItemGroup>
  • Сохраните все. Закройте файл .csproj в Visual Studio. Кликните правой кнопкой мыши свой проект в Solution Explorer и выберите Reload Project. Перестройте и убедитесь, что нет ошибок.

Отличная новость, вы только что обновили файл своего проекта до нового SDK-стиля! Проект все еще таргетирован на .NET Framework, но теперь вы сможете перенастроить его на .NET Core.

Шаг 3 – Ретаргет на .NET Core


Откройте файл проекта, дважды кликнув его в Solution Explorer. Найдите свойство TargetFramework и измените значение на netcoreapp3.0. Теперь ваш файл проекта должен выглядеть так:


<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    ...
  </PropertyGroup>
  ...
</Project>

Постройте и запустите свой проект. Поздравляем, вы перенесли его на .NET Core 3!

Исправление ошибок


Если вы столкнулись с такими ошибками, как

The type or namespace <some name> could not be found

или

The name <some name> does not exist in the current context

а ваш Portability Report отображался зеленым, то знайте – их легко исправить, просто добавив пакет NuGet с соответствующей библиотекой. Если же вам не удается найти пакет NuGet с отсутствующей библиотекой, то попробуйте обратиться к Microsoft.Windows.Compatibility. Этот пакет добавляет ~21K API .NET из .NET Framework.

Работа с конструкторами


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

  • Конструктор WPF уже находится в preview-режиме, и мы работаем над добавлением к нему дополнительных функций.
  • Конструктор WinForms для .NET Core будет доступен позже, так что пока вы можете использовать конструктор WinForms для .NET Framework в качестве обходного пути.

Вот как можно использовать конструктор WinForms для .NET Framework:

  1. Скопируйте файл .csproj (допустим, MyProject.csproj), дайте ему другое имя, например, MyProject.NetFramework.csproj и поместите его рядом с существующим файлом проекта.
  2. Убедитесь, что ваш проект закрыт в Visual Studio, откройте новый проект MyProject.NetFramework.csproj.
    В Solution Explorer щелкните правой кнопкой мыши свой проект и выберите Properties. На вкладке Application (должна открываться по умолчанию) задайте для Assembly name и Default namespace те же значения, что и в исходном проекте (удалите “.NetFramework” из имен).
    Сохраните это решение рядом с существующим решением.
  3. Откройте новый файл проекта и измените TargetFramework на net472.
  4. Теперь, когда вам нужно использовать конструктор WinForms, загрузите ваш проект с MyProject.NetFramework.csproj, и вы сможете начать работу с конструктором .NET Framework. Когда вы с ним закончите, закройте и откройте ваш проект с файлом проекта .NET Core.
  5. Это всего лишь обходной путь до тех пор, пока конструктор WinForms для .NET Core не будет готов.

Почему стоит переходить на .NET Core


Посмотрите видео, где мы со Скоттом Хантером (Scott Hunter) рассказываем обо всех новинках, связанных с .NET Core 3. Переход на .NET Core 3.0.

Комментарии (18)


  1. MonkAlex
    10.06.2019 10:08

    Ждём пока github.com/hvanbakel/CsprojToVs2017 выпустит апдейт под эти миграции. Не руками же это делать, в самом деле.


  1. samhuawey
    10.06.2019 10:26

    Так и не понял зачем авторам статьи нужна Visual Studio. И вообще вопрос к адептам .NET — есть ли возможность для сборки и деплоймента проекта .NET Core пользоваться стандартными средствами типа Maven, Jenkins, или нужно обязательно устанавливать Windows и покупать лицензии.


    1. ArSoron
      10.06.2019 11:02

  1. DeXPeriX
    10.06.2019 11:04

    Всё жду недождусь когда WinForms приложения можно будет в Linux на .Net Core перенести.


    1. MonkAlex
      10.06.2019 11:13

      А разве кто-то обещал? Речь только про замену рантайма с одного нетфрейморка на другой. Работать будет всё так же на Windows.


      1. DeXPeriX
        10.06.2019 11:14

        Не обещал. Но мечтать то никто не запрещал! :-)


      1. DancingOnWater
        10.06.2019 16:58
        +1

        WinForms сейчас работает на Моно и неплохо работает.


    1. esata
      10.06.2019 12:59
      +1

      1. DeXPeriX
        10.06.2019 14:11

        Оно скорее WPF чем WinForms. И насколько я знаю, чуть ли не едиснтвенный возможный кроссплатформенный UI для Windows/Linux. Может есть что-то ещё?


        1. a-tk
          10.06.2019 14:55

          Не надо путать XAML и WPF.


          1. DeXPeriX
            10.06.2019 14:59

            Простите, больше не буду. Но позвольте мне хотя бы и дальше путать XAML и WinForms!


            1. a-tk
              10.06.2019 21:41

              XAML — это всего лишь язык разметки для создания объектных древовидных структур. Разметка активно используется в WPF, но не только. UWP, Xamarin, Avalonia — это XAML, но не WPF.
              Более того, на сайте Microsoft есть статья, как сделать разметку WinForms на XAML: code.msdn.microsoft.com/windowsdesktop/use-xaml-to-design-winform-75d73893 (не спрашивайте у меня зачем).


        1. Marwin
          10.06.2019 23:04

          еще есть Uno Platform. Причем оно даже умеет в webassembly и мобилки. Однако я недавно попробовал сэмплы webassembly, которые буквально вешают хром сотнями метров либ… и что-то решил еще немного подождать с ними до лучших времен.


          1. DeXPeriX
            11.06.2019 13:14

            Звучит интересно. А Linux и Mac OS X умеет?


            1. Marwin
              11.06.2019 13:22

              пока нет, в макоси они типо ждут марципан.


          1. kekekeks
            12.06.2019 13:33

            У Uno есть очень интересная особенность: огромное количество типов из UWP там представляют из себя заглушки наподобие вот этой. А поскольку разрабатывать они предлагают с использованием штатных средств UWP, получаем NotImplementedException после уже после деплоя на устройство.


            Что касается WASM, то оно там безбожно тормозит, что предсказуемо.


        1. wlbm_onizuka
          11.06.2019 01:43

          Есть еще вот такая штука, я её успешно заюзал для WPF в Unity
          www.noesisengine.com/developers/downloads.php
          Но она оказывается принципиально рендерит его сама в OpenGL, я скачал пример для консольного приложения и тоже все запустилось и работает.

          WPF под Unity сбилдил на мобилку — все сразу заработало
          .net Core приложение с WPF под линукс пока завести поленился, но очень похоже что работать будет)

          капля дегтя: платно от суммы вроде 100к долларов в год


        1. Karen
          11.06.2019 14:59
          +1