Новые возможности .NET Core 3.0

В этой статье описываются новые возможности в .NET Core 3.0. Одно из основных усовершенствований — это поддержка классических приложений Windows (только Windows). С помощью пакета SDK для .NET Core 3.0 под названием Windows Desktop можно переносить приложения Windows Forms и Windows Presentation Foundation (WPF). Следует уточнить, что компонент Windows Desktop поддерживается и включен только в Windows. Дополнительные сведения см. далее в этой статье, в разделе Рабочий стол Windows.

В .NET Core 3.0 добавлена поддержка C# 8.0. Настоятельно рекомендуется использовать Visual Studio 2019 версии 16.3 или более поздней, Visual Studio для Mac 8.3 или более поздней или Visual Studio Code с последним расширением C#.

Скачайте .NET Core 3.0 и начните работу прямо сейчас в Windows, macOS или Linux.

Дополнительные сведения см. в объявлении о выпуске .NET Core 3.0.

Релиз-кандидат 1 .NET Core 3.0 считался корпорацией Майкрософт готовым к эксплуатации и полностью поддерживался. Если вы используете предварительную версию, необходимо перейти на версию RTM, чтобы продолжать получать поддержку.

Улучшения C# 8.0

В этот выпуск также входит версия C# 8.0, в которой появились ссылочные типы, допускающие значение NULL, асинхронные потоки и другие шаблоны. Дополнительные сведения о функциях C# 8.0 см. в разделе Новые возможности C# 8.0.

Учебники по функциям языка C# 8.0:

Добавлены улучшения языка для поддержки следующих функций API:

.NET Standard 2.1

.NET Core 3.0 реализует .NET Standard 2.1. При этом шаблон dotnet new classlib по умолчанию создает проект, который по-прежнему предназначен для .NET Standard 2.0. Чтобы создать проект для .NET Standard 2.1, откройте файл проекта и измените значение свойства TargetFramework на netstandard2.1:

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

  <PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
  </PropertyGroup>

</Project>

Если вы используете Visual Studio, у вас должна быть версия Visual Studio 2019, так как Visual Studio 2017 не поддерживает .NET Standard 2.1 или .NET Core 3.0.

Компиляция и развертывание

Исполняемые файлы по умолчанию

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

Во время выполнения команды dotnet build или dotnet publish создается исполняемый файл (называемый appHost), который соответствует среде и платформе используемого пакета SDK. Предполагается, что с этими исполняемыми файлами можно выполнять те же действия, что и с другими исполняемыми файлами в машинном коде, например:

  • исполняемый файл можно дважды щелкнуть;
  • приложение можно запустить из командной строки напрямую, например myapp.exe в Windows и ./myapp в Linux и macOS.

Файл appHost в macOS и заверение

Только macOS

Начиная с заверенного пакета SDK для .NET Core 3.0 для macOS параметр, отвечающий за создание исполняемого файла по умолчанию (называемого appHost), отключен по умолчанию. Дополнительные сведения см. в статье Заверение macOS Catalina и влияние на скачиваемые файлы и проекты .NET Core.

Если параметр appHost включен, .NET Core создает собственный исполняемый файл Mach-O, когда вы выполняете сборку или публикацию. Приложение выполняется в контексте appHost при запуске из исходного кода с помощью команды dotnet run или путем непосредственного запуска исполняемого файла Mach-O.

Без appHost пользователь может запустить приложение, зависящее от платформы, только одним способом — с помощью команды dotnet <filename.dll>. AppHost всегда создается при публикации приложения в автономном виде.

Можно либо настроить appHost на уровне проекта, либо переключить использование appHost для определенной команды dotnet с помощью параметра -p:UseAppHost:

  • Файл проекта

    <PropertyGroup>
      <UseAppHost>true</UseAppHost>
    </PropertyGroup>
    
  • Параметр командной строки

    dotnet run -p:UseAppHost=true
    

Дополнительные сведения о параметре UseAppHost см. в разделе Свойства MSBuild для Microsoft.NET.Sdk.

Однофайловые исполняемые файлы

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

Чтобы опубликовать однофайловый исполняемый файл, задайте PublishSingleFile в своем проекте или в командной строке с помощью команды dotnet publish:

<PropertyGroup>
  <RuntimeIdentifier>win10-x64</RuntimeIdentifier>
  <PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>

–или–

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

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

Обрезка сборок

Пакет SDK для .NET Core 3.0 содержит инструмент, который позволяет уменьшить размер приложения, анализируя промежуточный язык и устраняя неиспользуемые сборки.

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

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

Чтобы включить этот инструмент, укажите в проекте параметр <PublishTrimmed> и опубликуйте автономное приложение:

<PropertyGroup>
  <PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
dotnet publish -r <rid> -c Release

Например, простейший шаблон консольного приложения hello world, который входит в стандартную поставку, при публикации достигает размера около 70 МБ. С помощью <PublishTrimmed> этот размер можно снизить до 30 МБ.

Важно учитывать, что приложения и платформы (в том числе ASP.NET Core и WPF), которые используют отражение или связанные динамические функции, могут стать неработоспособными после обрезки. Такие нарушения возникают потому, что средство обрезки ничего не знает о динамическом поведении и не может определить, какие типы платформы потребуются для отражения. Но вы можете настроить средство обрезки IL так, чтобы оно учитывало этот сценарий.

В любом случае обязательно протестируйте приложение после обрезки.

Дополнительные сведения о средстве обрезки IL вы найдете в этой документации или на страницах репозитория mono/linker.

Многоуровневая компиляция

Многоуровневая компиляция (МК) по умолчанию входит только в .NET Core 3.0. Эта функция позволяет среде выполнения более адаптивно использовать компилятор JIT для повышения производительности.

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

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

  • Если метод имеет скомпилированный в режиме Ahead Of Time код (ReadyToRun), используется предварительно сформированный код.
  • В противном случае производится JIT-компиляция. Как правило, эти методы являются универсальными для типов значений.
    • Быстрая JIT-компиляция позволяет быстрее создавать код с более низким качеством (менее оптимизированный). В .NET Core 3.0 быстрая JIT-компиляция по умолчанию включена для методов, которые не содержат циклов, и является предпочтительной при запуске.
    • JIT-компиляция с полной оптимизацией позволяет создать высококачественный (более оптимизированный) код. Но на это уходит больше времени. Для методов, где не применяется быстрая JIT-компиляция (например, если метод имеет атрибут MethodImplOptions.AggressiveOptimization), используется JIT-компиляция с полной оптимизацией.

Для часто вызываемых методов JIT-компилятор в конечном итоге создает полностью оптимизированный код в фоновом режиме. После этого оптимизированный код заменяет предварительно скомпилированный код для данного метода.

Код, созданный быстрой JIT-компиляцией, может выполняться медленнее, выделять больше памяти или использовать больше пространства стека. При возникновении проблем быструю JIT-компиляцию можно отключить с помощью следующего свойства MSBuild в файле проекта.

<PropertyGroup>
  <TieredCompilationQuickJit>false</TieredCompilationQuickJit>
</PropertyGroup>

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

<PropertyGroup>
  <TieredCompilation>false</TieredCompilation>
</PropertyGroup>

Совет

При внесении изменений в эти параметры в файле проекта может потребоваться выполнить чистую сборку, чтобы они вступили в силу (удалите каталоги obj и bin и перестройте проект).

Дополнительные сведения о настройке компиляции во время выполнения см. в статье Параметры конфигурации времени выполнения для компиляции.

Образы ReadyToRun

Вы можете снизить время запуска приложения .NET Core, скомпилировав все сборки приложения в формат ReadyToRun (R2R). R2R является разновидностью компиляции AOT.

Бинарные файлы R2R повышают производительность при запуске, снижая объем работы, выполняемой на этом этапе компилятором JIT. Бинарные файлы содержат такой же машинный код, который создается компилятором JIT. Но бинарные файлы R2R имеют больший размер, так как содержат не только код на промежуточном языке (IL), который по-прежнему необходим для некоторых сценариев, но и версию того же кода на машинном языке. Функция R2R доступна только при публикации автономного приложения, предназначенного для конкретной среды выполнения (RID), например для Windows x64 или Linux x64.

Чтобы скомпилировать проект как ReadyToRun, выполните следующие действия:

  1. Добавьте в проект параметр <PublishReadyToRun>:

    <PropertyGroup>
      <PublishReadyToRun>true</PublishReadyToRun>
    </PropertyGroup>
    
  2. Опубликуйте автономное приложение. Например, такая команда создает автономное приложение для 64-разрядной версии Windows:

    dotnet publish -c Release -r win-x64 --self-contained
    

Ограничения при работе с несколькими платформами и архитектурами

Компилятор ReadyToRun пока не поддерживает перекрестное нацеливание. Компиляцию необходимо выполнять в конкретной целевой среде. Например, если вам нужен образ R2R для 64-разрядной ОС Windows, команду публикации следует выполнять именно в этой среде.

Исключения для кроссплатформенного таргетирования:

  • Windows x64 можно использовать для компиляции образов Windows Arm32, Arm64 и x86.
  • Windows x86 можно использовать для компиляции образов Windows Arm32.
  • Linux x64 можно использовать для компиляции образов Linux Arm32 и Arm64.

Дополнительные сведения см. в статье о ReadyToRun.

Среда выполнения и пакет SDK

Накат основной версии среды выполнения

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

  • Свойство файла проекта: RollForward
  • Свойство файла конфигурации среды выполнения: rollForward
  • Переменная среды: DOTNET_ROLL_FORWARD
  • Аргумент командной строки: --roll-forward

Необходимо указать одно из следующих значений. Если параметр не указан, ему по умолчанию присваивается значение Minor.

  • LatestPatch
    Накат до версии с наибольшим номером исправления. Отключает накат дополнительных версий.
  • Minor
    Накат до дополнительной версии со следующим по порядку возрастания номером, если запрошенная дополнительная версия отсутствует. Если запрошенная дополнительная версия присутствует, используется политика LatestPatch.
  • Major
    Накат до основной версии со следующим по порядку возрастания или дополнительной версии с наименьшим номером, если запрошенная дополнительная версия отсутствует. Если запрошенная основная версия присутствует, используется политика Minor.
  • LatestMinor
    Накат до дополнительной версии с наибольшим номером, даже если запрошенная дополнительная версия присутствует. Предназначен для сценариев размещения компонентов.
  • LatestMajor
    Накат до основной версии с наибольшим номером и дополнительной версии с наибольшим номером, даже если запрошенная основная версия присутствует. Предназначен для сценариев размещения компонентов.
  • Отключить
    Накат не выполняется. Привязка только к указанной версии. Эта политика не рекомендуется для общего использования, поскольку отключает возможность наката до последних исправлений. Это значение рекомендуется использовать только для тестирования.

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

Если запрашиваемая версия (как указано в .runtimeconfig.json для приложения) является версией выпуска, по умолчанию для наката предназначаются только такие версии. Все предварительные версии игнорируются. Если соответствующая версия выпуска отсутствует, учитываются предварительные версии. Это поведение можно изменить, установив значение DOTNET_ROLL_FORWARD_TO_PRERELEASE=1. В этом случае будут учитываться все версии.

Сборка копирует зависимости

Команда dotnet build копирует зависимости NuGet для вашего приложения из кэша NuGet в выходную папку сборки. Ранее зависимости копировались только в рамках выполнения команды dotnet publish.

Для некоторых операций, таких как обрезка и публикация страницы Razor, по-прежнему будет требоваться публикация.

Локальные средства

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

Локальные средства используют имя файла манифеста dotnet-tools.json в текущем каталоге. Этот файл манифеста определяет, какие средства доступны в этой папке и далее. Файл манифеста можно распространять вместе с кодом, чтобы те же средства мог восстановить и использовать любой, кто работает с вашим кодом.

Для глобальных и локальных средств требуется совместимая версия среды выполнения. Сейчас на сайте NuGet.org многие средства предназначены для среды выполнения .NET Core 2.1. Чтобы установить эти средства глобально или локально, нужно, как и раньше, установить среду выполнения NET Core 2.1.

Новые параметры global.json

Файл Global. JSON содержит новые параметры, которые позволяют более гибко определять требуемую версию пакета SDK для .NET Core. Эти новые параметры перечислены ниже.

  • allowPrerelease: указывает, следует ли сопоставитель пакета SDK учитывать предварительные версии при выборе используемой версии пакета SDK.
  • rollForward: указывает политику отката, используемую при выборе версии пакета SDK, либо в качестве резервной копии, если определенная версия пакета SDK отсутствует или в качестве директивы для использования более поздней версии.

Дополнительные сведения об изменениях, в том числе значения по умолчанию, поддерживаемые значения и новые правила сопоставления, см. в разделе общих сведений о global.json.

Уменьшенные размеры куч сборки мусора

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

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

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

Сборщик мусора теперь можно настраивать с помощью параметра GCLargePages как дополнительной функции, позволяющей выделять большие страницы в Windows.

Классическое приложение Windows и модель COM

Установщик пакета SDK Windows для .NET Core

Начиная с .NET Core 3.0, установщик MSI для Windows был изменен. Установщики пакетов SDK теперь обновляют дополнительные пакеты функций SDK на месте. Пакеты функций определяют сотни в обозначении исправления в номере версии. Например, в версиях 3.0.101 и 3.0.201 пакеты функций различаются, а в версиях 3.0.101 и 3.0.199 — одинаковы. При установке пакета SDK для .NET Core 3.0.101 пакет SDK для .NET Core 3.0.100, если он есть на компьютере, удаляется. Когда на тот же компьютер устанавливается пакет SDK для .NET Core 3.0.200, пакет SDK для .NET Core 3.0.101 удаляться не будет.

Дополнительные сведения об управлении версиями см. в разделе Общие сведения об управлении версиями в .NET Core.

Классические приложения для Windows

.NET Core 3.0 поддерживает классические приложения Windows с помощью Windows Presentation Foundation (WPF) и Windows Forms. Эти платформы также поддерживают использование современных элементов управления и стилей Fluent из библиотеки XAML пользовательского интерфейса Windows (WinUI) через острова XAML.

Компонент Windows Desktop является частью пакета SDK .NET Core 3.0 для Windows.

Вы можете создать приложение WPF или Windows Forms с помощью следующих команд dotnet:

dotnet new wpf
dotnet new winforms

Visual Studio 2019 добавляет шаблоны Новый проект для .NET Core 3.0 Windows Forms и WPF.

Дополнительные сведения о переносе существующего приложения .NET Framework см. в разделах Перенос проектов WPF и Перенос проектов Windows Forms.

Высокое разрешение для WinForms

Приложения .NET Core Windows Forms могут устанавливать режим высокого разрешения экрана с помощью Application.SetHighDpiMode(HighDpiMode). Метод SetHighDpiMode задает соответствующий режим высокого разрешения, если параметр не задан другими способами, например с помощью App.Manifest или P/Invoke перед Application.Run.

Возможны следующие значения highDpiMode, выраженные перечислением System.Windows.Forms.HighDpiMode:

  • DpiUnaware
  • SystemAware
  • PerMonitor
  • PerMonitorV2
  • DpiUnawareGdiScaled

См. о разработке классических приложений с поддержкой высокого разрешения экрана в Windows.

Создание компонентов COM

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

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

Пример того, как создать и использовать компонент COM, см. в разделе Демонстрация COM.

Собственное взаимодействие Windows

Windows предоставляет собственный API с широкими возможностями в виде API C, COM и WinRT. При том что .NET Core поддерживает P/Invoke, в .NET Core 3.0 добавлена возможность воссоздавать API COM и активировать API WinRT. Пример кода см. в разделе Демонстрация Excel.

Развертывание MSIX

MSIX — это новый формат пакета приложения Windows. Его можно использовать для развертывания классических приложений .NET Core 3.0 для Windows 10.

Проект упаковки приложений Windows, доступный в Visual Studio 2019, позволяет создавать пакеты MSIX с автономными приложениями .NET Core.

Файл проекта .NET Core должен указывать поддерживаемые среды выполнения в свойстве <RuntimeIdentifiers>:

<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>

Усовершенствования Linux

SerialPort для Linux

.NET Core 3.0 обеспечивает базовую поддержку System.IO.Ports.SerialPort в Linux.

Раньше среда .NET Core поддерживала SerialPort только в Windows.

Дополнительные сведения об ограниченной поддержке последовательного порта в Linux см. в описании проблемы № 33146 на сайте GitHub.

Ограничения памяти в Docker и cgroup

Запуск .NET Core 3.0 на платформе Linux с помощью Docker лучше работает с ограничениями памяти в cgroup. Запуск контейнера Docker с ограничениями памяти, например с docker run -m, изменяет поведение .NET Core.

  • Размер кучи сборщика мусора (GC) по умолчанию составляет не более 20 МБ или 75 % от ограничения памяти для контейнера.
  • Конкретный размер можно указать абсолютным числом или в виде процента от ограничения cgroup.
  • Минимальный зарезервированный размер сегмента в куче GC составляет 16 МБ. При использовании такого размера количество создаваемых на компьютерах куч будет меньше.

Поддержка GPIO для Raspberry Pi

В NuGet выпущено два новых пакета, которые можно использовать для программирования GPIO:

Пакеты GPIO содержат API для устройств GPIO, SPI, I2C и PWM. Пакет привязок Интернета вещей содержит привязки устройств. Дополнительные сведения см. в репозитории GitHub устройств.

Поддержка Arm64 Linux

.NET Core 3.0 добавляет поддержку Arm64 для Linux. Основной вариант использования Для Arm64 в настоящее время используется в сценариях Интернета вещей. Дополнительные сведения см. в статье о состоянии Arm64 .NET Core.

Образы Docker для .NET Core в Arm64 доступны для Alpine, Debian и Ubuntu.

Примечание.

Поддержка операционных систем macOS Arm64 (или Apple Silicon) и Windows Arm64 была добавлена в .NET 6.

Безопасность

TLS 1.3 и OpenSSL 1.1.1 в Linux

Теперь .NET Core использует преимущества поддержки TLS 1.3 в OpenSSL 1.1.1, когда она доступна в данной среде. В TLS 1.3:

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

В системе Linux .NET Core 3.0 по возможности использует OpenSSL 1.1.1, OpenSSL 1.1.0 или OpenSSL 1.0.2. Если есть доступ к OpenSSL 1.1.1, оба типа, System.Net.Security.SslStream и System.Net.Http.HttpClient, используют TLS 1.3 (при условии что клиент и сервер поддерживают TLS 1.3).

В следующем примере C# 8.0 показано, как .NET Core 3.0 в Ubuntu 18.10 подключается к https://www.cloudflare.com:

using System;
using System.Net.Security;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace whats_new
{
    public static class TLS
    {
        public static async Task ConnectCloudFlare()
        {
            var targetHost = "www.cloudflare.com";

            using TcpClient tcpClient = new TcpClient();

            await tcpClient.ConnectAsync(targetHost, 443);

            using SslStream sslStream = new SslStream(tcpClient.GetStream());

            await sslStream.AuthenticateAsClientAsync(targetHost);
            await Console.Out.WriteLineAsync($"Connected to {targetHost} with {sslStream.SslProtocol}");
        }
    }
}

Шифры криптографии

В .NET Core 3.0 добавлена поддержка шифров AES-GCM и AES-CCM, реализованных с помощью System.Security.Cryptography.AesGcm и System.Security.Cryptography.AesCcm соответственно. Оба этих алгоритма представляют собой алгоритмы AEAD (аутентифицированного шифрования с присоединенными данными).

В следующем коде показано использование шифра AesGcm для шифрования и расшифровки случайных данных.

using System;
using System.Linq;
using System.Security.Cryptography;

namespace whats_new
{
    public static class Cipher
    {
        public static void Run()
        {
            // key should be: pre-known, derived, or transported via another channel, such as RSA encryption
            byte[] key = new byte[16];
            RandomNumberGenerator.Fill(key);

            byte[] nonce = new byte[12];
            RandomNumberGenerator.Fill(nonce);

            // normally this would be your data
            byte[] dataToEncrypt = new byte[1234];
            byte[] associatedData = new byte[333];
            RandomNumberGenerator.Fill(dataToEncrypt);
            RandomNumberGenerator.Fill(associatedData);

            // these will be filled during the encryption
            byte[] tag = new byte[16];
            byte[] ciphertext = new byte[dataToEncrypt.Length];

            using (AesGcm aesGcm = new AesGcm(key))
            {
                aesGcm.Encrypt(nonce, dataToEncrypt, ciphertext, tag, associatedData);
            }

            // tag, nonce, ciphertext, associatedData should be sent to the other part

            byte[] decryptedData = new byte[ciphertext.Length];

            using (AesGcm aesGcm = new AesGcm(key))
            {
                aesGcm.Decrypt(nonce, ciphertext, tag, decryptedData, associatedData);
            }

            // do something with the data
            // this should always print that data is the same
            Console.WriteLine($"AES-GCM: Decrypted data is {(dataToEncrypt.SequenceEqual(decryptedData) ? "the same as" : "different than")} original data.");
        }
    }
}

Импорт и экспорт криптографических ключей

.NET Core 3.0 поддерживает импорт и экспорт асимметричных открытых и закрытых ключей из стандартных форматов. Сертификат X.509 использовать не нужно.

Все типы ключей, включая RSA, DSA, ECDsa и ECDiffieHellman, поддерживают следующие форматы:

  • Открытый ключ

    • X.509 SubjectPublicKeyInfo
  • Закрытый ключ

    • PKCS#8 PrivateKeyInfo
    • PKCS#8 EncryptedPrivateKeyInfo

Ключи RSA также поддерживают:

  • Открытый ключ

    • PKCS#1 RSAPublicKey
  • Закрытый ключ

    • PKCS#1 RSAPrivateKey

Методы экспорта создают двоичные данные в кодировке DER, а методы импорта выполняют то же самое. Если ключ хранится в формате PEM в виде текста, вызывающему объекту потребуется выполнить декодирование содержимого в формате base64, прежде чем вызывать метод импорта.

using System;
using System.Security.Cryptography;

namespace whats_new
{
    public static class RSATest
    {
        public static void Run(string keyFile)
        {
            using var rsa = RSA.Create();

            byte[] keyBytes = System.IO.File.ReadAllBytes(keyFile);
            rsa.ImportRSAPrivateKey(keyBytes, out int bytesRead);

            Console.WriteLine($"Read {bytesRead} bytes, {keyBytes.Length - bytesRead} extra byte(s) in file.");
            RSAParameters rsaParameters = rsa.ExportParameters(true);
            Console.WriteLine(BitConverter.ToString(rsaParameters.D));
        }
    }
}

Файлы PKCS 8 можно проверять с помощью System.Security.Cryptography.Pkcs.Pkcs8PrivateKeyInfo, а файлы PFX/PKCS #12 — с помощью System.Security.Cryptography.Pkcs.Pkcs12Info. Для манипуляций с файлами PFX/PKCS #12 можно использовать System.Security.Cryptography.Pkcs.Pkcs12Builder.

Изменения API .NET Core 3.0

Диапазоны и индексы

Новый тип System.Index можно использовать для индексирования. Вы можете создать с помощью int индекс, который отсчитывается с начала, а с помощью оператора ^ префикса (C#) индекс, который отсчитывается с конца:

Index i1 = 3;  // number 3 from beginning
Index i2 = ^4; // number 4 from end
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6"

Кроме того, есть тип System.Range, который состоит из двух значений Index (одно для начала и одно для конца) и который можно написать с помощью выражения диапазона x..y (C#). После этого можно выполнить индексацию с помощью команды Range, которая создает срез:

var slice = a[i1..i2]; // { 3, 4, 5 }

Дополнительные сведения см. в руководстве по диапазонам и индексам.

Асинхронные потоки

Тип IAsyncEnumerable<T> — это новая асинхронная версия IEnumerable<T>. Язык позволяет выполнить действие await foreach с этими объектами IAsyncEnumerable<T>, чтобы использовать их элементы, и действие yield return по отношению к ним, чтобы создать элементы.

В приведенном ниже примере демонстрируется создание и применение асинхронных потоков. Инструкция foreach является асинхронной и использует yield return, чтобы создать асинхронные потоки для вызывающих объектов. Этот шаблон (с использованием yield return) является рекомендуемой моделью для создания асинхронных потоков.

async IAsyncEnumerable<int> GetBigResultsAsync()
{
    await foreach (var result in GetResultsAsync())
    {
        if (result > 20) yield return result;
    }
}

Помимо возможности await foreach вы также можете создать асинхронные итераторы, например, итератор, который возвращает IAsyncEnumerable/IAsyncEnumerator, для которого можно применить await и yield. Для объектов, которые необходимо удалить, можно использовать IAsyncDisposable, который реализовывают различные типы BCL, такие как Stream и Timer.

Дополнительные сведения см. в руководстве по асинхронным потокам.

IEEE с плавающей запятой

API плавающей запятой сейчас обновляются, чтобы соответствовать редакции IEEE 754-2008. Цель этих изменений заключается в том, чтобы предоставлять все необходимые операции и гарантировать, что они соответствуют спецификации IEEE. Дополнительные сведения об улучшениях с плавающей запятой см . в статье об улучшениях синтаксического анализа с плавающей запятой и форматирования в записи блога .NET Core 3.0 .

Исправления синтаксического анализа и форматирования включают:

  • Правильный анализ и округление входных данных любой длины.
  • Правильный анализ и форматирование отрицательного нуля.
  • Правильный анализ Infinity и NaN с помощью проверки без учета регистра и допущения необязательного + в начале, где это применимо.

Новый API System.Math включают:

  • BitIncrement(Double) и BitDecrement(Double).
    Соответствует операциям IEEE nextUp и nextDown. Они возвращают наименьшее число с плавающей запятой, которое может быть больше или меньше входных данных (соответственно). Например, Math.BitIncrement(0.0) вернет double.Epsilon.

  • MaxMagnitude(Double, Double) и MinMagnitude(Double, Double).
    Соответствуют операциям IEEE maxNumMag и minNumMag. Они возвращают значение, которое будет больше или меньше из двух величин (соответственно). Например, Math.MaxMagnitude(2.0, -3.0) вернет -3.0.

  • ILogB(Double)
    Соответствует операции IEEE logB, которая возвращает целочисленное значение. Она возвращает целочисленный логарифм по основанию 2 входного параметра. Этот метод действует практически так же, как floor(log2(x)), но с минимальными погрешностями округления.

  • ScaleB(Double, Int32)
    Соответствует операции IEEE scaleB, которая принимает целочисленное значение. Возвращает x * pow(2, n), но выполняется с минимальными погрешностями округления.

  • Log2(Double)
    Соответствует операции IEEE log2. Возвращает логарифм по основанию 2. Сводит к минимуму погрешность округления.

  • FusedMultiplyAdd(Double, Double, Double)
    Соответствует операции IEEE fma. Выполняет умножение и сложение. То есть он выполняет (x * y) + z как одну операцию, тем самым сводя к минимуму погрешность округления. Например, FusedMultiplyAdd(1e308, 2.0, -1e308) возвращает 1e308. Стандартный (1e308 * 2.0) - 1e308 возвращает double.PositiveInfinity.

  • CopySign(Double, Double)
    Соответствует операции IEEE copySign. Возвращает значение x, но со знаком y.

Встроенные объекты, зависимые от платформы .NET

Были добавлены API-интерфейсы, которые разрешают доступ к определенным инструкциям ЦП, ориентированным на производительность, например SIMD или наборы инструкций побитовой обработки. Эти инструкции помогут значительно улучшить производительность в некоторых сценариях, таких как эффективная параллельная обработка данных.

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

Дополнительные сведения см. в разделе Встроенные объекты, зависимые от платформы .NET.

Улучшенные API версий .NET Core

Начиная с .NET Core 3.0, API версий, предоставляемые с .NET Core, возвращают те данные, которые должны. Например:

System.Console.WriteLine($"Environment.Version: {System.Environment.Version}");

// Old result
//   Environment.Version: 4.0.30319.42000
//
// New result
//   Environment.Version: 3.0.0
System.Console.WriteLine($"RuntimeInformation.FrameworkDescription: {System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription}");

// Old result
//   RuntimeInformation.FrameworkDescription: .NET Core 4.6.27415.71
//
// New result (notice the value includes any preview release information)
//   RuntimeInformation.FrameworkDescription: .NET Core 3.0.0-preview4-27615-11

Предупреждение

Критическое изменение. С технической точки зрения это изменение является критическим, поскольку изменилась схема управления версиями.

Быстрая встроенная поддержка JSON

Пользователи .NET в основном полагались на Newtonsoft.Json и другие популярные библиотеки JSON, которые по-прежнему остаются хорошими вариантами. Newtonsoft.Json использует в качестве базового типа данных строки .NET, которые обладают внутренней структурой UTF-16.

Новая встроенная поддержка JSON отличается высокой производительностью, малым распределением и поддержкой текста JSON в кодировке UTF-8. Дополнительные сведения о пространстве имен и типах System.Text.Json см. в следующих статьях:

Поддержка HTTP/2

Тип System.Net.Http.HttpClient поддерживает протокол HTTP/2. Если протокол HTTP/2 включен, версия протокола HTTP согласуется через TLS/ALPN, а HTTP/2 используется, только если его выбрал сервер.

Протоколом по умолчанию остается HTTP/1.1, но у вас есть два способа включить HTTP/2. Во-первых, можно указать использование HTTP/2 в заголовке запроса:

var client = new HttpClient() { BaseAddress = new Uri("https://localhost:5001") };

// HTTP/1.1 request
using (var response = await client.GetAsync("/"))
    Console.WriteLine(response.Content);

// HTTP/2 request
using (var request = new HttpRequestMessage(HttpMethod.Get, "/") { Version = new Version(2, 0) })
using (var response = await client.SendAsync(request))
    Console.WriteLine(response.Content);

Во-вторых, можно изменить HttpClient для использования HTTP/2 по умолчанию:

var client = new HttpClient()
{
    BaseAddress = new Uri("https://localhost:5001"),
    DefaultRequestVersion = new Version(2, 0)
};

// HTTP/2 is default
using (var response = await client.GetAsync("/"))
    Console.WriteLine(response.Content);

При разработке приложений часто требуется подключение без шифрования. Если вы знаете, что целевая конечная точка использует протокол HTTP/2, вы можете включить незашифрованные подключения для HTTP/2. Для этого задайте переменной среды DOTNET_SYSTEM_NET_HTTP_SOCKETSHTTPHANDLER_HTTP2UNENCRYPTEDSUPPORT значение 1 или включите этот параметр в контексте приложения:

AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

Следующие шаги