ААА! Пришло время переписывать на .NET Coreǃ
Все мы давно хотим перелезть на .NET Core, но постоянно что-то мешает. Например, ничего не поделаешь, когда не хватает важных API. В версии 2.0 процесс упростили благодаря .NET Standard 2.0, но это ещё не всё. Ну что ж, Microsoft-боги вняли нашим молитвам и завезли 20 000 API, доступных в виде одного-единственного пакета в NuGet!
Кому это вообще нужно?
Вкратце, это нужно всем. Имхо, сама возможность перетащить свои тонны легаси на .NET Core — уже достаточное оправдание для любых жертв.
Скептикам же надо как бы напомнить, что .NET Core пилится специально для масштабируемых веб-приложений на всех разумных операционных системах (GNU/Linux, macOS и Windows), а более точно выбрать между Core и Framework поможет специальный документ.
Как это использовать?
Во-первых, надо понять, что залежи легаси сами собой не разгребутся. Нечего даже и думать о том, чтобы схватить в охапку миллион классов и перетащить их одной кнопкой.
Предположим, вы накодили приложуху на ASP.NET MVC для Windows-локалхоста, и вас за это не уволили. Настало время перетащить ее на правоверный Linux, работающий на Azure! Лучше есть слона по кусочкам, а именно:
- Перетащить всё на ASP.NET Core (но целевой платформой продолжать держать .NET Framework);
- Переползти на .NET Core (но продолжать юзать Windows);
- Перепрыгнуть на GNU/Linux;
- Запуститься на Azure.
Понятно, что к этому великому плану стоит подходить не как к строительству коммунизма, а разумно. Например, если нужно показать биг боссам запуск на Azure — с этого и стоит начать. Если же думать лень (мне, например, точно лень), наши лидеры написали специальную методичку по обретению веры в .NET Core.
Вкратце, нужно расчехлить NuGet, поставить пакет Microsoft.Windows.Compatibility и обнаружить, что стала доступна огромная куча разных нужных и ненужных API.
Важно понимать, что этот самый Microsoft.Windows.Compatibility всё еще яростно допиливается, так что все офигительные истории нам только предстоят.
Сейчас имеется следующий набор ништяков (таблица получилась огромная; чувак, читающий этот пост с мобилы: прости меня пожалуйста!):
Компонент | Статус | Windows-Only |
---|---|---|
Microsoft.Win32.Registry | Available | Yes |
Microsoft.Win32.Registry.AccessControl | Available | Yes |
System.CodeDom | Available | |
System.ComponentModel.Composition | Coming | |
System.Configuration.ConfigurationManager | Available | |
System.Data.DatasetExtensions | Coming | |
System.Data.Odbc | Coming | |
System.Data.SqlClient | Available | |
System.Diagnostics.EventLog | Coming | Yes |
System.Diagnostics.PerformanceCounter | Coming | Yes |
System.DirectoryServices | Coming | Yes |
System.DirectoryServices.AccountManagement | Coming | Yes |
System.DirectoryServices.Protocols | Coming | |
System.Drawing | Coming | |
System.Drawing.Common | Available | |
System.IO.FileSystem.AccessControl | Available | Yes |
System.IO.Packaging | Available | |
System.IO.Pipes.AccessControl | Available | Yes |
System.IO.Ports | Available | Yes |
System.Management | Coming | Yes |
System.Runtime.Caching | Coming | |
System.Security.AccessControl | Available | Yes |
System.Security.Cryptography.Cng | Available | Yes |
System.Security.Cryptography.Pkcs | Available | Yes |
System.Security.Cryptography.ProtectedData | Available | Yes |
System.Security.Cryptography.Xml | Available | Yes |
System.Security.Permissions | Available | |
System.Security.Principal.Windows | Available | Yes |
System.ServiceModel.Duplex | Available | |
System.ServiceModel.Http | Available | |
System.ServiceModel.NetTcp | Available | |
System.ServiceModel.Primitives | Available | |
System.ServiceModel.Security | Available | |
System.ServiceModel.Syndication | Coming | |
System.ServiceProcess.ServiceBase | Coming | Yes |
System.ServiceProcess.ServiceController | Available | Yes |
System.Text.Encoding.CodePages | Available | Yes |
System.Threading.AccessControl | Available | Yes |
А что делать с Windows-only API?
Страдать, чо.
Для танкистов. Не все API одинаково переносимы. Если ты остаешься на Windows, проблем никаких нет. Если же хочешь приобщиться к святости Ричарда Столлмана и Тима Кука на GNU/Linux и macOS соответственно, придется страдать.
Взглянув на табличку ништяков, видим: Windows-only компонентов там чуть ли не половина. Добрые Microsoft-боги, тем не менее, позволяют успешно компилировать такой код под любой платформой. При попытке использования несуществующей фичи мы наткнемся на PlatformNotSupportedException
в рантайме, поэтому все такие фичи нужно будет густо обмазать вызовами RuntimeInformation.IsOSPlatform()
:
private static string GetLoggingPath()
{
// Verify the code is running on Windows.
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
using (var key = Registry.CurrentUser.OpenSubKey(@"Software\Fabrikam\AssetManagement"))
{
if (key?.GetValue("LoggingDirectoryPath") is string configuredPath)
return configuredPath;
}
}
// This is either not running on Windows or no logging path was configured,
// so just use the path for non-roaming user-specific data files.
var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
return Path.Combine(appDataPath, "Fabrikam", "AssetManagement", "Logging");
}
Как же понять, какая API-шка будет работать только в Windows? Документацию ведь никто не читает, верно?
Дорогой мой любитель программирования копипастой со StackOverflow! Microsoft — боги суровые, но справедливые, поэтому буквально пару недель назад они запилили API Analyzer tool. С помощью Roslyn эта тула помечает Windows-only API, причем только тогда, когда целью выставлен .NET Core или .NET Standard.
Что делать с ошибками? Как было сказано ранее, страдать.
- Удалять непортируемый код. Зачем нужна фича, если она не запускается на macOS? :-)
- Усердно рефакторить код с помощью других, более кроссплатформенных API. Благо это обновление принесло таких во множестве.
- Расставить проверки на тип операционки в тех местах, где происходят GNU/Linux-специфичные вещи, которые просто не нужны в Windows.
В примере с картинки кто-то пытается вычитать настроечку в Реестре. Можно обернуть эту строчку в проверку, выполнять ее только на Windows. В GNU/Linux эквивалент этой строчки будет другим, куда более мучительным.
Заметьте, что Windows Compatibility Pack — это метапакет. В Microsoft отлично понимали, что обычные люди не будут мучиться с выискиванием отдельных мелких пакетиков и захотят перейти на новую платформу одним прыжком (с учетом оговорок выше). Тем не менее, если ты — вдумчивый крутой разработчик, то можно притаскивать фичи и поодиночке. Таким образом, можно будет выкинуть куда больше зависимостей на ненужный хлам.
Что дальше?
Морально готовишься к портированию. Устанавливаешь Windows Compatibility Pack. Изучаешь ништяки, коих там более 20 тысяч, включая EventLog, WMI, Performance Counters, Windows Services итп.
Если хочешь сделать приложуху кроссплатформенной — запускаешь API Analyzer. Можно предварительно немного поплакать или тяпнуть водочки.
К сожалению, сейчас .NET Core не покрывает нужды десктопной разработки. Возможно, когда-нибудь это изменится. Но это уже совсем другая история.