День 2507. #ЧтоНовенького #NET11
Помощник по MIME-типам в .NET 11
Как обычно, сразу за выходом новой версии .NET, сразу начинаем обсуждать потенциальные новинки следующей версии. .NET 11 обещают выход новых хелпер-методов: MediaTypeMap.GetMediaType и MediaTypeMap.GetExtension, которые значительно упростят веб-разработку!
MediaTypeMap.GetMediaType
Основная идея заключается в получении MIME-типов из указанного файла или расширения:
Мы также можем использовать «обратный поиск» с помощью MediaTypeMap.GetExtension:
Заметьте, что известные расширения начинаются с точки.
См. также:
Обсуждение на GitHub: https://github.com/dotnet/runtime/issues/121017
Полный пул-реквест: https://github.com/dotnet/runtime/pull/121776
Источник: https://steven-giesel.com/blogPost/8f41d316-f6ac-4712-bf11-ea36b7c2f2e6/mime-type-helper-in-net-11
Помощник по MIME-типам в .NET 11
Как обычно, сразу за выходом новой версии .NET, сразу начинаем обсуждать потенциальные новинки следующей версии. .NET 11 обещают выход новых хелпер-методов: MediaTypeMap.GetMediaType и MediaTypeMap.GetExtension, которые значительно упростят веб-разработку!
MediaTypeMap.GetMediaType
Основная идея заключается в получении MIME-типов из указанного файла или расширения:
using System.Net.Mime;
// text/css
_ = MediaTypeMap.GetMediaType("myfile.css");
// application/json
_ = MediaTypeMap.GetMediaType("resource.json");
_ = MediaTypeMap.GetMediaType("rEsOuRCe.JsOn");
// null, т.к. smith – неизвестное расширение
_ = MediaTypeMap.GetMediaType("jon.smith");
// Он также работает с расширениями или с целыми путями
// text/css
_ = MediaTypeMap.GetMediaType("/home/user/myfile.css");
_ = MediaTypeMap.GetMediaType("css");
Мы также можем использовать «обратный поиск» с помощью MediaTypeMap.GetExtension:
using System.Net.Mime;
// ".pdf"
_ = MediaTypeMap.GetExtension("application/pdf");
// ".jpg"
_ = MediaTypeMap.GetExtension("image/jpeg");
// null для неизвестных
_ = MediaTypeMap.GetExtension("madeup/mimetype");
_ = MediaTypeMap.GetExtension("/some/path/basic.css");
Заметьте, что известные расширения начинаются с точки.
См. также:
Обсуждение на GitHub: https://github.com/dotnet/runtime/issues/121017
Полный пул-реквест: https://github.com/dotnet/runtime/pull/121776
Источник: https://steven-giesel.com/blogPost/8f41d316-f6ac-4712-bf11-ea36b7c2f2e6/mime-type-helper-in-net-11
4👍6
День 2546. #ЧтоНовенького #NET11
Аргументы Выражений Коллекций в C #15
В репозитории .NET появилось неплохое предложение, которое немного улучшит работу с выражениями коллекций — предоставление пользователям возможности передавать аргументы при создании.
Замечание: пока это только предложение, и оно может появиться в C# 15 (или, вероятно, позже), а может и никогда.
Что такое выражения коллекций?
Вкратце: выражения коллекций — это альтернативный синтаксис для создания коллекций в C#:
Естественно, это работает не только с List<T>, но и с любым типом, который реализует определённый шаблон. См. подробнее.
Преимущество в том, что синтаксис более лаконичен, а в некоторых случаях, возможно, и улучшается производительность.
Но и это можно улучшить!
Здесь в случае с all компилятор создаст новый List с нужной ёмкостью:
Но бывают случаи, когда компилятор не знает, сколько элементов будет в коллекции, а вы знаете (например, при обращении к базе данных). Сейчас у нас нет возможности указать ёмкость списка в выражении коллекции. Но предлагаемый вариант позволит это изменить. Как уже говорилось ранее, это всего лишь предложение, и синтаксис, используемый в следующем примере, не окончательный (и, откровенно говоря, выглядит он пока странно):
Это сразу создаст список вместимостью 32 (хотя это и не очень полезно, но суть понятна). В итоге получится
Источник: https://steven-giesel.com/blogPost/352fe495-9cc4-4df8-8ad1-a3e26a64185c/collection-expression-arguments-in-c-15
Аргументы Выражений Коллекций в C #15
В репозитории .NET появилось неплохое предложение, которое немного улучшит работу с выражениями коллекций — предоставление пользователям возможности передавать аргументы при создании.
Замечание: пока это только предложение, и оно может появиться в C# 15 (или, вероятно, позже), а может и никогда.
Что такое выражения коллекций?
Вкратце: выражения коллекций — это альтернативный синтаксис для создания коллекций в C#:
List<int> evens = [2, 4, 6, 8, 10];
List<int> odds = [1, 3, 5, 7, 9];
// Сливаем обе коллекции и добавляем 0 в начало
List<int> all = [0, ..evens, ..odds];
Естественно, это работает не только с List<T>, но и с любым типом, который реализует определённый шаблон. См. подробнее.
Преимущество в том, что синтаксис более лаконичен, а в некоторых случаях, возможно, и улучшается производительность.
Но и это можно улучшить!
Здесь в случае с all компилятор создаст новый List с нужной ёмкостью:
num2 = 1 + (list4.Count + list5.Count);
List<int> list6 = new List<int>(num2);
Но бывают случаи, когда компилятор не знает, сколько элементов будет в коллекции, а вы знаете (например, при обращении к базе данных). Сейчас у нас нет возможности указать ёмкость списка в выражении коллекции. Но предлагаемый вариант позволит это изменить. Как уже говорилось ранее, это всего лишь предложение, и синтаксис, используемый в следующем примере, не окончательный (и, откровенно говоря, выглядит он пока странно):
List<int> all =
[args(capacity: 32), 0, ..evens, ..odds];
Это сразу создаст список вместимостью 32 (хотя это и не очень полезно, но суть понятна). В итоге получится
new List<int>(32);. Это может пригодиться и в других случаях. Например, HashSet<T> позволяет передавать IEqualityComparer<T> для сравнения строк:HashSet<string> names =
[args(comparer: StringComparer.OrdinalIgnoreCase), "Alice", "Bob", "alice"];
Источник: https://steven-giesel.com/blogPost/352fe495-9cc4-4df8-8ad1-a3e26a64185c/collection-expression-arguments-in-c-15
👍7👎1
День 2582. #ЧтоНовенького #NET11
Вышла Превью 1 .NET 11. Начало
Команда Microsoft .NET выпустила первую предварительную версию .NET 11. Про главную особенность превью – асинхронную обработку в среде выполнения – я уже писал. Теперь рассмотрим другие важные новинки.
Библиотеки
1. Добавлена нативная поддержка сжатия Zstandard (zstd) благодаря новому классу ZstandardStream. Zstandard обеспечивает значительно более быстрое сжатие и распаковку по сравнению с существующими алгоритмами, сохраняя при этом конкурентоспособные коэффициенты сжатия. Новые API включают полный набор возможностей потокового, однократного и словарного сжатия и распаковки.
2. В ZipArchiveEntry добавлены:
- параметр FileAccess, позволяющий указать, тип доступа к открываемому файлу FileAccess.Read или FileAccess.Write;
- свойство CompressionMethod в ZipArchiveEntry типа перечисления ZipCompressionMethod, позволяющее приложениям определять алгоритм сжатия для каждой записи.
3. Добавлены аргументы выражений коллекций с ключевым словом with и поддержка выражений коллекций для FrozenDictionary:
4. Поддержка рун в String, StringBuilder и TextWriter
System.Text.Rune теперь можно использовать гораздо шире. Это значительно упрощает корректную работу приложений с текстом Unicode, особенно для символов, находящихся за пределами базовой многоязычной плоскости, которые требуют суррогатных пар при представлении в виде символов:
5. Помощник по MIME-типам System.Net.Mime.MediaTypeMap
6. API для проверки HMAC и KMAC
Добавлены методы Verify ко всем классам HMAC и KMAC. Значения HMAC часто необходимо сравнивать за фиксированное время, чтобы предотвратить атаки по времени. Ранее это требовало двух шагов: вычисления HMAC с помощью HashData, а затем сравнения с помощью CryptographicOperations.FixedTimeEquals. Новые методы Verify объединяют оба этапа в один безопасный вызов.
7. DivisionRounding для целочисленного деления
Добавлена поддержка альтернативных режимов округления при целочисленном делении с помощью нового перечисления DivisionRounding и новых методов в IBinaryInteger<T>: Divide, DivRem и Remainder. Большинство аппаратных средств реализуют деление нацело (/ и % в C#), но разные языки и предметные области требуют округления до большего или меньшего целого числа, евклидова округления или округления от нуля. Хотя это довольно тривиально, новые API позволяют выбрать правильный режим и хорошо оптимизированную реализацию:
Окончание следует…
Источник: https://github.com/dotnet/core/tree/main/release-notes/11.0/preview/preview1
Вышла Превью 1 .NET 11. Начало
Команда Microsoft .NET выпустила первую предварительную версию .NET 11. Про главную особенность превью – асинхронную обработку в среде выполнения – я уже писал. Теперь рассмотрим другие важные новинки.
Библиотеки
1. Добавлена нативная поддержка сжатия Zstandard (zstd) благодаря новому классу ZstandardStream. Zstandard обеспечивает значительно более быстрое сжатие и распаковку по сравнению с существующими алгоритмами, сохраняя при этом конкурентоспособные коэффициенты сжатия. Новые API включают полный набор возможностей потокового, однократного и словарного сжатия и распаковки.
// Сжатие с ZstandardStream
using var compressStream =
new ZstandardStream(outputStream, CompressionMode.Compress);
await inputStream.CopyToAsync(compressStream);
// Распаковка
using var decompressStream
= new ZstandardStream(inputStream, CompressionMode.Decompress);
await decompressStream.CopyToAsync(outputStream);
2. В ZipArchiveEntry добавлены:
- параметр FileAccess, позволяющий указать, тип доступа к открываемому файлу FileAccess.Read или FileAccess.Write;
- свойство CompressionMethod в ZipArchiveEntry типа перечисления ZipCompressionMethod, позволяющее приложениям определять алгоритм сжатия для каждой записи.
3. Добавлены аргументы выражений коллекций с ключевым словом with и поддержка выражений коллекций для FrozenDictionary:
FrozenDictionary<string, int> lookup =
[with(StringComparer.Ordinal), "one":1, "two":2, "three":3];
4. Поддержка рун в String, StringBuilder и TextWriter
System.Text.Rune теперь можно использовать гораздо шире. Это значительно упрощает корректную работу приложений с текстом Unicode, особенно для символов, находящихся за пределами базовой многоязычной плоскости, которые требуют суррогатных пар при представлении в виде символов:
var s = "Hello 🌍";
var glb = new Rune(0x1F30D); // 🌍
s.Contains(glb); // true
s.IndexOf(glb); // 6
s.StartsWith(glb); // false
s.Replace(glb, new Rune('X')); // "Hello X"
5. Помощник по MIME-типам System.Net.Mime.MediaTypeMap
6. API для проверки HMAC и KMAC
Добавлены методы Verify ко всем классам HMAC и KMAC. Значения HMAC часто необходимо сравнивать за фиксированное время, чтобы предотвратить атаки по времени. Ранее это требовало двух шагов: вычисления HMAC с помощью HashData, а затем сравнения с помощью CryptographicOperations.FixedTimeEquals. Новые методы Verify объединяют оба этапа в один безопасный вызов.
7. DivisionRounding для целочисленного деления
Добавлена поддержка альтернативных режимов округления при целочисленном делении с помощью нового перечисления DivisionRounding и новых методов в IBinaryInteger<T>: Divide, DivRem и Remainder. Большинство аппаратных средств реализуют деление нацело (/ и % в C#), но разные языки и предметные области требуют округления до большего или меньшего целого числа, евклидова округления или округления от нуля. Хотя это довольно тривиально, новые API позволяют выбрать правильный режим и хорошо оптимизированную реализацию:
int truncated =
int.Divide(-7, 2, DivisionRounding.Truncate); // -3
int floored =
int.Divide(-7, 2, DivisionRounding.Floor); // -4
// всегда неотрицательный
int euclideanRem =
int.Remainder(-7, 3, DivisionRounding.Euclidean); // 2
// Получаем частное и остаток сразу
var (q, r) =
int.DivRem(-7, 2, DivisionRounding.Floor); // q=-4, r=1
Окончание следует…
Источник: https://github.com/dotnet/core/tree/main/release-notes/11.0/preview/preview1
1👍10
День 2583. #ЧтоНовенького #NET11
Вышла Превью 1 .NET 11. Окончание
Начало
.NET MAUI
1. Генерация исходного кода XAML по умолчанию в .NET MAUI. Чтобы вернуться к XAMLC, нужно добавить в файл проекта:
2. CoreCLR в качестве среды выполнения Android по умолчанию для релизных сборок. Это должно улучшить совместимость с остальными компонентами .NET, а также сократить время запуска при разумном увеличении размера приложения. Чтобы вернуться к Mono:
3. Интерактивный выбор целевой платформы и устройства для
Blazor
1. Новый компонент EnvironmentBoundary позволяет осуществлять условный рендеринг в зависимости от среды хостинга, аналогично тег-хелперу environment в MVC:
2. Blazor WebAssembly теперь поддерживает IHostedService для запуска фоновых сервисов в браузере и может получать доступ к переменным среды через IConfiguration для настройки во время выполнения без пересборки приложения.
3. Фреймворк также добавляет новые компоненты Label и DisplayName для форм. Они будут отображать значения из атрибутов [Display] или [DisplayName] свойства:
4. Добавлено событие щелчка по строкам в QuickGrid.
5. Относительная навигация в NavigationManager.NavigateTo() и NavLink с помощью опции RelativeToCurrentUri="true".
6. Шаблон проекта Blazor Web App теперь поддерживает опцию «Добавить поддержку контейнеризации» в Visual Studio.
ASP.NET Core
1. OpenAPI для конечных точек, возвращающих FileContentResult, теперь будет генерировать соответствующую документацию схемы:
2. Новый интерфейс IOutputCachePolicyProvider для динамических политик кэширования вывода. Этот интерфейс позволяет приложениям определять базовую политику кэширования по умолчанию, проверять наличие именованных политик и поддерживать сложные сценарии, в которых политики должны определяться динамически. Примерами являются загрузка политик из внешних источников конфигурации, баз данных или применение правил кэширования, специфичных для конкретного клиента.
3. Сертификаты разработчика в средах WSL теперь автоматически считаются доверенными как в WSL, так и в Windows.
Источник: https://github.com/dotnet/core/tree/main/release-notes/11.0/preview/preview1
Вышла Превью 1 .NET 11. Окончание
Начало
.NET MAUI
1. Генерация исходного кода XAML по умолчанию в .NET MAUI. Чтобы вернуться к XAMLC, нужно добавить в файл проекта:
<PropertyGroup>
<MauiXamlInflator>XamlC</MauiXamlInflator>
</PropertyGroup>
2. CoreCLR в качестве среды выполнения Android по умолчанию для релизных сборок. Это должно улучшить совместимость с остальными компонентами .NET, а также сократить время запуска при разумном увеличении размера приложения. Чтобы вернуться к Mono:
<PropertyGroup>
<UseMonoRuntime>true</UseMonoRuntime>
</ProperyGroup>
3. Интерактивный выбор целевой платформы и устройства для
dotnet run. Теперь после запуска в консоли вам будет предложен выбор целевой платформы или устройства/эмулятора (если их несколько).Blazor
1. Новый компонент EnvironmentBoundary позволяет осуществлять условный рендеринг в зависимости от среды хостинга, аналогично тег-хелперу environment в MVC:
<EnvironmentBoundary Include="Development,Staging">
<p>Pre-production environment</p>
</EnvironmentBoundary>
2. Blazor WebAssembly теперь поддерживает IHostedService для запуска фоновых сервисов в браузере и может получать доступ к переменным среды через IConfiguration для настройки во время выполнения без пересборки приложения.
3. Фреймворк также добавляет новые компоненты Label и DisplayName для форм. Они будут отображать значения из атрибутов [Display] или [DisplayName] свойства:
<Label For="() => model.Name" />
4. Добавлено событие щелчка по строкам в QuickGrid.
5. Относительная навигация в NavigationManager.NavigateTo() и NavLink с помощью опции RelativeToCurrentUri="true".
6. Шаблон проекта Blazor Web App теперь поддерживает опцию «Добавить поддержку контейнеризации» в Visual Studio.
ASP.NET Core
1. OpenAPI для конечных точек, возвращающих FileContentResult, теперь будет генерировать соответствующую документацию схемы:
FileContentResult:
type: string
format: binary
2. Новый интерфейс IOutputCachePolicyProvider для динамических политик кэширования вывода. Этот интерфейс позволяет приложениям определять базовую политику кэширования по умолчанию, проверять наличие именованных политик и поддерживать сложные сценарии, в которых политики должны определяться динамически. Примерами являются загрузка политик из внешних источников конфигурации, баз данных или применение правил кэширования, специфичных для конкретного клиента.
3. Сертификаты разработчика в средах WSL теперь автоматически считаются доверенными как в WSL, так и в Windows.
Источник: https://github.com/dotnet/core/tree/main/release-notes/11.0/preview/preview1
1👍7
День 2602. #ЧтоНовенького #NET11
Объединения Наконец Появятся в .NET? Начало
После многих лет раздумий, обсуждений дизайна и костылей на уровне библиотек, объединения наконец-то становятся полноценной частью C#. Предложение в репозитории языка C# больше не является отдалённой идеей. Теперь, похоже, что эта функция появилась в превью 2 .NET 11 в качестве одной из ранних возможностей C# 15.
Это важно, потому что объединения решают проблему моделирования, которая существовала в C# очень давно: значение часто имеет ровно одну из нескольких допустимых форм, но система типов не имела встроенного способа выразить это замкнутое множество. В результате обычно использовалось что-то из следующего: обнуляемое значение, управление потоком через исключение, логический флаг или написанная вручную обёртка для результата.
Что именно есть в предложении?
Предложение шире, чем просто единая синтаксическая форма. Оно определяет модель объединений для языка и лаконичный синтаксис объявления поверх этой модели. На высоком уровне предложение вводит 4 возможности, которые важны в повседневном коде (поведения объединения):
1. Неявные преобразования из типов-вариантов в тип объединения;
2. Сопоставление по образцу, которое автоматически распаковывает содержимое объединения;
3. Проверка полноты в выражениях switch, что охвачены все типы-варианты;
4. Улучшения обнуляемости для содержимого объединения.
Основной синтаксис прост:
Это объявление означает, что Pet может содержать ровно один из этих типов-вариантов. Компилятор разрешает прямое построение через значения вариантов и рассматривает сопоставление с образцом в Pet как работу с замкнутым множеством.
Вариант
Типы-объединения и объявления объединения — не одно и то же
C# не просто добавляет форму объявления объединения… Он также определяет, что такое тип-объединение.
Согласно предложению, любой класс или структура, помеченные атрибутом
1. Объединения разработаны как языковая возможность, которая может выходить за рамки объявлений, генерируемых компилятором. Существующие или написанные вручную типы также могут использовать эту модель.
2. Это оставляет место для специализированных реализаций. Сокращённое объявление, показанное выше, намеренно оставлено нечётким, но языковая модель шире, чем это сокращённое объявление.
Окончание следует…
Источник: https://medium.com/@benjaminabt/c-15-unions-unions-are-finally-in-net-ben-abt-f4493c1e9ffc
Объединения Наконец Появятся в .NET? Начало
После многих лет раздумий, обсуждений дизайна и костылей на уровне библиотек, объединения наконец-то становятся полноценной частью C#. Предложение в репозитории языка C# больше не является отдалённой идеей. Теперь, похоже, что эта функция появилась в превью 2 .NET 11 в качестве одной из ранних возможностей C# 15.
Это важно, потому что объединения решают проблему моделирования, которая существовала в C# очень давно: значение часто имеет ровно одну из нескольких допустимых форм, но система типов не имела встроенного способа выразить это замкнутое множество. В результате обычно использовалось что-то из следующего: обнуляемое значение, управление потоком через исключение, логический флаг или написанная вручную обёртка для результата.
Что именно есть в предложении?
Предложение шире, чем просто единая синтаксическая форма. Оно определяет модель объединений для языка и лаконичный синтаксис объявления поверх этой модели. На высоком уровне предложение вводит 4 возможности, которые важны в повседневном коде (поведения объединения):
1. Неявные преобразования из типов-вариантов в тип объединения;
2. Сопоставление по образцу, которое автоматически распаковывает содержимое объединения;
3. Проверка полноты в выражениях switch, что охвачены все типы-варианты;
4. Улучшения обнуляемости для содержимого объединения.
Основной синтаксис прост:
public union Pet(Cat, Dog, Bird);
Это объявление означает, что Pet может содержать ровно один из этих типов-вариантов. Компилятор разрешает прямое построение через значения вариантов и рассматривает сопоставление с образцом в Pet как работу с замкнутым множеством.
public sealed record Cat(string Name);
public sealed record Dog(string Name);
public sealed record Bird(string Name);
public union Pet(Cat, Dog, Bird);
public static string Describe(Pet pet) =>
pet switch
{
Cat cat => $"Cat: {cat.Name}",
Dog dog => $"Dog: {dog.Name}",
Bird bird => $"Bird: {bird.Name}"
};
Вариант
default не требуется, т.к. объединение считается исчерпывающим после обработки всех типов-вариантов.Типы-объединения и объявления объединения — не одно и то же
C# не просто добавляет форму объявления объединения… Он также определяет, что такое тип-объединение.
Согласно предложению, любой класс или структура, помеченные атрибутом
[Union], могут участвовать в поведении объединения (см. 4 варианта выше), если они предоставляют необходимые открытые члены. Т.е. в язык добавляется новый паттерн обработки, а не просто ключевое слово union. Это важно по двум причинам:1. Объединения разработаны как языковая возможность, которая может выходить за рамки объявлений, генерируемых компилятором. Существующие или написанные вручную типы также могут использовать эту модель.
2. Это оставляет место для специализированных реализаций. Сокращённое объявление, показанное выше, намеренно оставлено нечётким, но языковая модель шире, чем это сокращённое объявление.
Окончание следует…
Источник: https://medium.com/@benjaminabt/c-15-unions-unions-are-finally-in-net-ben-abt-f4493c1e9ffc
👍20
День 2603. #ЧтоНовенького #NET11
Объединения Наконец Появятся в .NET? Окончание
Начало
Объявление объединения намеренно размыто
Предложение чётко определяет представление по умолчанию, выбранное для объявлений объединений. Объявление преобразуется в простую структуру со свойством Value типа object и сгенерированным конструктором для каждого типа-варианта. Это означает, что:
- Оно компактно.
- Типы-вариантов в виде типов-значений упаковываются при хранении через форму объявления по умолчанию.
Это не случайность. Предложение позиционирует объявления объединений как простой и широко применимый вариант по умолчанию. Для многих случаев на уровне приложений это правильный компромисс. В результатах, получаемых из сервисов, команд, парсинга и т.п. часто важны ясность и корректность, а не эффективность использования памяти.
Тем не менее, в предложении также признаётся, что этот вариант по умолчанию не будет идеальным для каждого сценария. Он явно оставляет место для пользовательских объединений и для паттернов доступа без упаковки, где структура и производительность имеют большее значение, чем компактное представление в одном поле.
Этот нюанс важен. Нативные объединения станут значительным улучшением для основного кода, но они не делают специализированные библиотеки объединений устаревшими. В основном они заменяют необходимость ручной разработки для распространённых случаев.
Зачем?
Важность объединении в коде C# заключается в возможности указать в системе типов, что операция имеет замкнутый набор допустимых результатов.
Рассмотрим сервис, который получает заказ. Во многих кодовых базах можно найти несколько вариантов реализации:
- тип возврата Order? (обнуляемый),
- исключение при отсутствии данных,
- пользовательская обёртка, которую не проверить, не открыв реализацию.
Объединение делает контракт видимым в прямо в сигнатуре:
Эта сигнатура документирует три типа-результата. Компилятор отвечает за корректность работы. Так объединения переносят проверки корректности на более ранние этапы, уменьшают скрытое управление потоком выполнения и значительно усложняют неправильное использование результатов.
Это также причина, по которой объединения органично вписываются в другие перспективные разработки C#, такие как закрытые иерархии типов и объявления вариантов. Язык движется к более чёткому пониманию замкнутых множеств и исчерпываемости, и объединения являются одним из наиболее ярких выражений этого направления.
Итого
Долгое время объединения в C# обсуждались как нечто, что есть в других языках, а в C# нет. Наконец, это будет не так. Интерес теперь заключается не в том, должны ли в C# быть объединения, а в том, как кодовые базы могут начать использовать преимущества этой модели уже сейчас.
Предложение C#15 наконец-то дает языку первоклассное решение для замкнутых форм результатов и исчерпывающей обработки. Это сочетание необычайно сильно.
Источник: https://medium.com/@benjaminabt/c-15-unions-unions-are-finally-in-net-ben-abt-f4493c1e9ffc
Объединения Наконец Появятся в .NET? Окончание
Начало
Объявление объединения намеренно размыто
Предложение чётко определяет представление по умолчанию, выбранное для объявлений объединений. Объявление преобразуется в простую структуру со свойством Value типа object и сгенерированным конструктором для каждого типа-варианта. Это означает, что:
- Оно компактно.
- Типы-вариантов в виде типов-значений упаковываются при хранении через форму объявления по умолчанию.
Это не случайность. Предложение позиционирует объявления объединений как простой и широко применимый вариант по умолчанию. Для многих случаев на уровне приложений это правильный компромисс. В результатах, получаемых из сервисов, команд, парсинга и т.п. часто важны ясность и корректность, а не эффективность использования памяти.
Тем не менее, в предложении также признаётся, что этот вариант по умолчанию не будет идеальным для каждого сценария. Он явно оставляет место для пользовательских объединений и для паттернов доступа без упаковки, где структура и производительность имеют большее значение, чем компактное представление в одном поле.
Этот нюанс важен. Нативные объединения станут значительным улучшением для основного кода, но они не делают специализированные библиотеки объединений устаревшими. В основном они заменяют необходимость ручной разработки для распространённых случаев.
Зачем?
Важность объединении в коде C# заключается в возможности указать в системе типов, что операция имеет замкнутый набор допустимых результатов.
Рассмотрим сервис, который получает заказ. Во многих кодовых базах можно найти несколько вариантов реализации:
- тип возврата Order? (обнуляемый),
- исключение при отсутствии данных,
- пользовательская обёртка, которую не проверить, не открыв реализацию.
Объединение делает контракт видимым в прямо в сигнатуре:
public sealed record NotFound;
public sealed record Unauthorized;
public sealed record Order(int Id);
public union GetOrderResult(Order, NotFound, Unauthorized);
Эта сигнатура документирует три типа-результата. Компилятор отвечает за корректность работы. Так объединения переносят проверки корректности на более ранние этапы, уменьшают скрытое управление потоком выполнения и значительно усложняют неправильное использование результатов.
Это также причина, по которой объединения органично вписываются в другие перспективные разработки C#, такие как закрытые иерархии типов и объявления вариантов. Язык движется к более чёткому пониманию замкнутых множеств и исчерпываемости, и объединения являются одним из наиболее ярких выражений этого направления.
Итого
Долгое время объединения в C# обсуждались как нечто, что есть в других языках, а в C# нет. Наконец, это будет не так. Интерес теперь заключается не в том, должны ли в C# быть объединения, а в том, как кодовые базы могут начать использовать преимущества этой модели уже сейчас.
Предложение C#15 наконец-то дает языку первоклассное решение для замкнутых форм результатов и исчерпывающей обработки. Это сочетание необычайно сильно.
Источник: https://medium.com/@benjaminabt/c-15-unions-unions-are-finally-in-net-ben-abt-f4493c1e9ffc
👍9
День 2609. #ЧтоНовенького #NET11
Обновления ASP.NET Core в Превью 2 .NET 11
1. ASP.NET Core теперь нативно добавляет атрибуты семантического соглашения OpenTelemetry к активности HTTP-сервера, что соответствует спецификации трассировки HTTP-сервера OpenTelemetry. Все необходимые атрибуты теперь включены по умолчанию, что соответствует метаданным, ранее доступным только через библиотеку OpenTelemetry.Instrumentation.AspNetCore.
Для сбора встроенных данных трассировки подпишитесь на источник активности Microsoft.AspNetCore в конфигурации OpenTelemetry:
Дополнительных библиотек инструментирования (например, OpenTelemetry.Instrumentation.AspNetCore) не требуется. Теперь фреймворк напрямую заполняет атрибуты семантических соглашений, такие как http.requesshenyun2024.top/t.method, url.path, http.response.status_code и server.address, в активности запроса.
Если вы не хотите, чтобы атрибуты OpenTelemetry добавлялись к активности, вы можете отключить это, установив параметр AppContext Microsoft.AspNetCore.Hosting.SuppressActivityOpenTelemetryData в true.
2. В Blazor Server-Side Rendering (SSR) теперь поддерживается TempData — механизм хранения данных, сохраняющийся между HTTP-запросами. TempData идеально подходит для таких сценариев, как всплывающие сообщения после отправки формы, передача данных при перенаправлениях (шаблон POST-Redirect-GET) и одноразовые уведомления.
3. Представлен новый шаблон проекта dotnet new webworker, позволяющий приложениям Blazor WebAssembly переносить ресурсоемкие вычисления на Web Worker без блокировки UI-потока, обеспечивая отзывчивость приложений во время ресурсоемких операций:
Шаблон генерирует класс
4. Поддержка OpenAPI 3.2.0 (Ломающее изменение)
Microsoft.AspNetCore.OpenApi теперь поддерживает OpenAPI 3.2.0 через обновлённую зависимость в Microsoft.OpenApi 3.3.1. Это обновление включает ломающие изменения в зависимых библиотеках. Детали в гайде по обновлению Microsoft.OpenApi. Чтобы сгененировать документ OpenAPI 3.2.0, укажите версию при вызове AddOpenApi():
В последующих обновлениях будут использованы новые возможности спецификации 3.2.0, такие как поддержка схем элементов для потоковых событий.
5. Парсер HTTP/1.1 запросов Kestrel был переработан, чтобы избежать генерации исключений при некорректных запросах. В сценариях с высокой интенсивностью некорректного трафика, таких как сканирование портов или неправильно настроенные клиенты, отмечено повышение пропускной способности на 20–40 процентов.
Источники:
- https://www.infoq.com/news/2026/03/dotnet-11-preview-2/
- https://github.com/dotnet/core/blob/main/release-notes/11.0/preview/preview2/aspnetcore.md
Обновления ASP.NET Core в Превью 2 .NET 11
1. ASP.NET Core теперь нативно добавляет атрибуты семантического соглашения OpenTelemetry к активности HTTP-сервера, что соответствует спецификации трассировки HTTP-сервера OpenTelemetry. Все необходимые атрибуты теперь включены по умолчанию, что соответствует метаданным, ранее доступным только через библиотеку OpenTelemetry.Instrumentation.AspNetCore.
Для сбора встроенных данных трассировки подпишитесь на источник активности Microsoft.AspNetCore в конфигурации OpenTelemetry:
builder.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddSource("Microsoft.AspNetCore")
.AddConsoleExporter());
Дополнительных библиотек инструментирования (например, OpenTelemetry.Instrumentation.AspNetCore) не требуется. Теперь фреймворк напрямую заполняет атрибуты семантических соглашений, такие как http.requesshenyun2024.top/t.method, url.path, http.response.status_code и server.address, в активности запроса.
Если вы не хотите, чтобы атрибуты OpenTelemetry добавлялись к активности, вы можете отключить это, установив параметр AppContext Microsoft.AspNetCore.Hosting.SuppressActivityOpenTelemetryData в true.
2. В Blazor Server-Side Rendering (SSR) теперь поддерживается TempData — механизм хранения данных, сохраняющийся между HTTP-запросами. TempData идеально подходит для таких сценариев, как всплывающие сообщения после отправки формы, передача данных при перенаправлениях (шаблон POST-Redirect-GET) и одноразовые уведомления.
3. Представлен новый шаблон проекта dotnet new webworker, позволяющий приложениям Blazor WebAssembly переносить ресурсоемкие вычисления на Web Worker без блокировки UI-потока, обеспечивая отзывчивость приложений во время ресурсоемких операций:
dotnet new webworker -n MyWebWorker
Шаблон генерирует класс
WebWorkerClient с фабрикой для создания экземпляров исполнителей. Методы исполнителя используют [JSExport] и могут быть вызваны из компонентов:await using var worker =
await WebWorkerClient.CreateAsync(JSRuntime);
var result = await worker
.InvokeAsync<string>("MyApp.MyWorker.Greet", ["World"]);
4. Поддержка OpenAPI 3.2.0 (Ломающее изменение)
Microsoft.AspNetCore.OpenApi теперь поддерживает OpenAPI 3.2.0 через обновлённую зависимость в Microsoft.OpenApi 3.3.1. Это обновление включает ломающие изменения в зависимых библиотеках. Детали в гайде по обновлению Microsoft.OpenApi. Чтобы сгененировать документ OpenAPI 3.2.0, укажите версию при вызове AddOpenApi():
builder.Services.AddOpenApi(options =>
{
options.OpenApiVersion =
Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_2;
});
В последующих обновлениях будут использованы новые возможности спецификации 3.2.0, такие как поддержка схем элементов для потоковых событий.
5. Парсер HTTP/1.1 запросов Kestrel был переработан, чтобы избежать генерации исключений при некорректных запросах. В сценариях с высокой интенсивностью некорректного трафика, таких как сканирование портов или неправильно настроенные клиенты, отмечено повышение пропускной способности на 20–40 процентов.
Источники:
- https://www.infoq.com/news/2026/03/dotnet-11-preview-2/
- https://github.com/dotnet/core/blob/main/release-notes/11.0/preview/preview2/aspnetcore.md
👍1
День 2662. #ЧтоНовенького #NET11
В .NET 11 Исключения Фоновых Сервисов Будут Всплывать
Ошибка, которая давно существовала в .NET: если BackgroundService генерировал исключение после первого await, хост перехватывал его, писал критическое сообщение в лог, а затем корректно завершал работу с кодом результата 0. Т.е. все думали, что процесс успешно завершился. Теперь это исправлено!
Проблема
Рассмотрим этот рабочий процесс:
До .NET 11 вывод был таким:
Процесс завершён с кодом 0 ??? Критическая ошибка в логе, но код результата всё равно 0.
Почему это так работало?
Если метод помечен как асинхронный, исключение перехватывалось функцией TryExecuteBackgroundServiceAsync глубоко внутри инфраструктуры, логировалось как критическое, после чего хост инициировал корректное завершение работы. Корректное завершение работы => код результата 0.
Если метод не помечен как асинхронный и выбрасывалось исключение, то процесс завершался с кодом ошибки.
Основная причина в том, что host.RunAsync() возвращает Task (а не Task<int>), и не было механизма для сигнализации о завершении процесса с кодом ошибки для фонового сервиса, который бы указывал на сбой.
Исправление в .NET 11
Теперь IHost.RunAsync() и IHost.StopAsync() будут передавать исключение из BackgroundService, а не игнорировать его. Теперь вы получите:
Если вам нужно старое поведение
Вы можете установить для параметра обработки исключений значение «Игнорировать»:
См. оригинальный ишью.
Источник: https://steven-giesel.com/blogPost/00fcb870-6bf7-4f97-824f-8eab1b8838be/backgroundservice-exceptions-now-propagate-in-net-11
В .NET 11 Исключения Фоновых Сервисов Будут Всплывать
Ошибка, которая давно существовала в .NET: если BackgroundService генерировал исключение после первого await, хост перехватывал его, писал критическое сообщение в лог, а затем корректно завершал работу с кодом результата 0. Т.е. все думали, что процесс успешно завершился. Теперь это исправлено!
Проблема
Рассмотрим этот рабочий процесс:
public class Worker : BackgroundService
{
protected override async Task
ExecuteAsync(CancellationToken stopToken)
{
await Task.Delay(TimeSpan.FromSeconds(1), stopToken);
throw new Exception("something went wrong");
}
}
До .NET 11 вывод был таким:
crit: Microsoft.Extensions.Hosting.Internal.Host[10]
The HostOptions.BackgroundServiceExceptionBehavior is configured to StopHost.
A BackgroundService has thrown an unhandled exception, and the IHost instance is stopping.
...
System.Exception: something went wrong
info: Microsoft.Hosting.Lifetime[0]
Application is shutting down...
Процесс завершён с кодом 0 ??? Критическая ошибка в логе, но код результата всё равно 0.
Почему это так работало?
Если метод помечен как асинхронный, исключение перехватывалось функцией TryExecuteBackgroundServiceAsync глубоко внутри инфраструктуры, логировалось как критическое, после чего хост инициировал корректное завершение работы. Корректное завершение работы => код результата 0.
Если метод не помечен как асинхронный и выбрасывалось исключение, то процесс завершался с кодом ошибки.
Основная причина в том, что host.RunAsync() возвращает Task (а не Task<int>), и не было механизма для сигнализации о завершении процесса с кодом ошибки для фонового сервиса, который бы указывал на сбой.
Исправление в .NET 11
Теперь IHost.RunAsync() и IHost.StopAsync() будут передавать исключение из BackgroundService, а не игнорировать его. Теперь вы получите:
crit: Microsoft.Extensions.Hosting.Internal.Host[10]
…
System.Exception: something went wrong
Unhandled exception. System.Exception: something went wrong
at Worker.ExecuteAsync(…)
Process finished with exit code 134. (или 1 в Windows)
Если вам нужно старое поведение
Вы можете установить для параметра обработки исключений значение «Игнорировать»:
services.Configure<HostOptions>(options =>
{
options.BackgroundServiceExceptionBehavior = BackgroundServiceExceptionBehavior.Ignore;
});
См. оригинальный ишью.
Источник: https://steven-giesel.com/blogPost/00fcb870-6bf7-4f97-824f-8eab1b8838be/backgroundservice-exceptions-now-propagate-in-net-11
👍19
День 2665. #ЧтоНовенького #NET11
Улучшения API процессов в .NET 11. Обзор
Класс System.Diagnostics.Process — это основной способ создания процессов и взаимодействия с ними в .NET. В .NET 11 в него внесли самое масштабное обновление за последние годы. Изменения добавляют высокоуровневые API, которые упрощают запуск процесса и перехват его вывода без взаимоблокировок, предоставляют полный контроль над наследованием дескрипторов и стандартным перенаправлением дескрипторов, вводят функции управления временем жизни, такие как KillOnParentExit, и включают в себя облегченный API на основе SafeProcessHandle, более удобный для оптимизации. В этой серии постов рассмотрим нововведения подробно.
Новые функции
1. Однострочник для выполнения процесса -
Запускает процесс, перехватывает вывод/ошибку, ожидает завершения — всё за один вызов.
2. Выполнение без перехвата вывода -
Запускает процесс и ожидает завершения без перехвата вывода.
3. Запустить и забыть -
Запускает процесс, возвращает его PID и немедленно освобождает все ресурсы.
4. Перехват вывода без взаимоблокировок -
Читает stdout и stderr одновременно с использованием мультиплексирования, избегая взаимоблокировок буфера канала.
5. Перенаправление -
Перенаправляет стандартные дескрипторы на файлы, каналы, null или любой SafeFileHandle.
6. Контролируемое наследование -
Точно указывает, какие дескрипторы наследуются дочерними процессами, предотвращая случайные утечки памяти.
7. Завершение при выходе родительского процесса -
Гарантирует завершение дочерних процессов при выходе родительского процесса (Windows и Linux).
8. Отсоединённые процессы -
Запускает процесс, который сохраняется после выхода родительского процесса, сигнала или закрытия терминала.
9. Легковесный дескриптор процесса -
Удобный для сокращения количества процессов низкоуровневый API для запуска и управления процессами без Process.
10. Подробная информация о завершении процесса -
Сообщает код завершения, сигнал завершения (Unix) и был ли процесс завершён из-за тайм-аута/отмены.
11. Нулевой дескриптор -
Открывает дескриптор, который отбрасывает операции записи и возвращает EOF при чтении.
12. Анонимные каналы -
Создаёт пару подключённых каналов с дополнительной поддержкой асинхронности.
13. Обработчики консоли -
Получает базовый дескриптор операционной системы для стандартных потоков.
14. Определение типа дескриптора -
Определяет, является ли дескриптор файлом, каналом, сокетом и т. д.
Далее рассмотрим новые функции подробнее.
Продолжение следует…
Источник: https://devblogs.microsoft.com/dotnet/process-api-improvements-in-dotnet-11/
Улучшения API процессов в .NET 11. Обзор
Класс System.Diagnostics.Process — это основной способ создания процессов и взаимодействия с ними в .NET. В .NET 11 в него внесли самое масштабное обновление за последние годы. Изменения добавляют высокоуровневые API, которые упрощают запуск процесса и перехват его вывода без взаимоблокировок, предоставляют полный контроль над наследованием дескрипторов и стандартным перенаправлением дескрипторов, вводят функции управления временем жизни, такие как KillOnParentExit, и включают в себя облегченный API на основе SafeProcessHandle, более удобный для оптимизации. В этой серии постов рассмотрим нововведения подробно.
Новые функции
1. Однострочник для выполнения процесса -
Process.RunAndCaptureText[Async]Запускает процесс, перехватывает вывод/ошибку, ожидает завершения — всё за один вызов.
2. Выполнение без перехвата вывода -
Process.Run[Async]Запускает процесс и ожидает завершения без перехвата вывода.
3. Запустить и забыть -
Process.StartAndForgetЗапускает процесс, возвращает его PID и немедленно освобождает все ресурсы.
4. Перехват вывода без взаимоблокировок -
Process.ReadAllText/Bytes/Lines[Async]Читает stdout и stderr одновременно с использованием мультиплексирования, избегая взаимоблокировок буфера канала.
5. Перенаправление -
ProcessStartInfo.Standard[Input/Output/Error]HandleПеренаправляет стандартные дескрипторы на файлы, каналы, null или любой SafeFileHandle.
6. Контролируемое наследование -
ProcessStartInfo.InheritedHandlesТочно указывает, какие дескрипторы наследуются дочерними процессами, предотвращая случайные утечки памяти.
7. Завершение при выходе родительского процесса -
ProcessStartInfo.KillOnParentExitГарантирует завершение дочерних процессов при выходе родительского процесса (Windows и Linux).
8. Отсоединённые процессы -
ProcessStartInfo.StartDetachedЗапускает процесс, который сохраняется после выхода родительского процесса, сигнала или закрытия терминала.
9. Легковесный дескриптор процесса -
SafeProcessHandle.Start/WaitForExit/Kill/SignalУдобный для сокращения количества процессов низкоуровневый API для запуска и управления процессами без Process.
10. Подробная информация о завершении процесса -
ProcessExitStatusСообщает код завершения, сигнал завершения (Unix) и был ли процесс завершён из-за тайм-аута/отмены.
11. Нулевой дескриптор -
File.OpenNullHandle()Открывает дескриптор, который отбрасывает операции записи и возвращает EOF при чтении.
12. Анонимные каналы -
SafeFileHandle.CreateAnonymousPipeСоздаёт пару подключённых каналов с дополнительной поддержкой асинхронности.
13. Обработчики консоли -
Console.OpenStandard[Input/Output/Error]Handle()Получает базовый дескриптор операционной системы для стандартных потоков.
14. Определение типа дескриптора -
SafeFileHandle.TypeОпределяет, является ли дескриптор файлом, каналом, сокетом и т. д.
Далее рассмотрим новые функции подробнее.
Продолжение следует…
Источник: https://devblogs.microsoft.com/dotnet/process-api-improvements-in-dotnet-11/
👍17
День 2666. #ЧтоНовенького #NET11
Улучшения API процессов в .NET 11. Продолжение
Обзор
Перехват выходных данных процесса без взаимоблокировок
Почему захват выходных данных процесса может приводить к зависанию
При перенаправлении стандартного вывода (stdout) и ошибок (stderr) процесса возможны взаимоблокировки. Понимание причин этого крайне важно для понимания сути новинок. Создадим приложение, которое пытается прочитать все выходные данные и ошибки процесса.
Прежде всего, нужно перенаправить stdout и stderr, чтобы иметь возможность их прочитать. Это делается путём установки свойств RedirectStandardOutput и RedirectStandardError объекта ProcessStartInfo в true. Перед запуском процесса создаются два выделенных канала (для вывода и для ошибок). Дочерний процесс записывает данные в свои stdout и stderr, как обычно, но вместо вывода в консоль данные записываются в каналы.
Каналы имеют ограниченный размер буфера (обычно 4КБ в Windows и 64КБ в Unix). Когда производитель (в нашем случае, дочерний процесс) записывает данные в канал, они сохраняются в буфере до тех пор, пока их не прочтёт потребитель (родительский процесс). Если производитель записывает больше данных, чем размер буфера, а потребитель одновременно не читает из канала, производитель будет заблокирован на операции записи, ожидая, пока потребитель прочитает из канала и освободит место в буфере.
Если потребитель ожидает завершения работы производителя (например, вызывая WaitForExit) без чтения из канала, он будет заблокирован, как только производитель заполнит буфер:
Перемещение
Причина в том, что мы читаем два потока последовательно, а не одновременно. Чтобы избежать этого, нужно одновременно очищать и стандартный вывод, и ошибку. До сих пор у нас было два варианта:
1. Использовать асинхронные операции чтения для StandardOutput и StandardError
2. Использовать события OutputDataReceived и ErrorDataReceived
События возникают при записи строки в stdout и stderr соответственно:
Существующие API не оптимальны с точки зрения простоты и производительности.
Продолжение следует…
Источник: https://devblogs.microsoft.com/dotnet/process-api-improvements-in-dotnet-11/
Улучшения API процессов в .NET 11. Продолжение
Обзор
Перехват выходных данных процесса без взаимоблокировок
Почему захват выходных данных процесса может приводить к зависанию
При перенаправлении стандартного вывода (stdout) и ошибок (stderr) процесса возможны взаимоблокировки. Понимание причин этого крайне важно для понимания сути новинок. Создадим приложение, которое пытается прочитать все выходные данные и ошибки процесса.
Прежде всего, нужно перенаправить stdout и stderr, чтобы иметь возможность их прочитать. Это делается путём установки свойств RedirectStandardOutput и RedirectStandardError объекта ProcessStartInfo в true. Перед запуском процесса создаются два выделенных канала (для вывода и для ошибок). Дочерний процесс записывает данные в свои stdout и stderr, как обычно, но вместо вывода в консоль данные записываются в каналы.
ProcessStartInfo startInfo = new("dotnet", "--help")
{
RedirectStandardOutput = true,
RedirectStandardError = true
};
using Process p = new() { StartInfo = startInfo };Каналы имеют ограниченный размер буфера (обычно 4КБ в Windows и 64КБ в Unix). Когда производитель (в нашем случае, дочерний процесс) записывает данные в канал, они сохраняются в буфере до тех пор, пока их не прочтёт потребитель (родительский процесс). Если производитель записывает больше данных, чем размер буфера, а потребитель одновременно не читает из канала, производитель будет заблокирован на операции записи, ожидая, пока потребитель прочитает из канала и освободит место в буфере.
Если потребитель ожидает завершения работы производителя (например, вызывая WaitForExit) без чтения из канала, он будет заблокирован, как только производитель заполнит буфер:
p.Start();
p.WaitForExit();
var output = p.StandardOutput.ReadToEnd();
var error = p.StandardError.ReadToEnd();
Перемещение
process.WaitForExit(); в конец тоже не помогает. ReadToEnd — блокирующий вызов: он читает до тех пор, пока поток не достигнет конца файла (EOF), что происходит только тогда, когда дочерний процесс закрывает свою часть канала (обычно при завершении). Поэтому в приведённом выше коде мы сначала блокируемся на stdout до завершения дочернего процесса, и только затем начинаем читать stderr. Если дочерний процесс записывает в stderr больше, чем может вместить буфер канала, он блокируется на своей записи — и мы застреваем во взаимоблокировке.Причина в том, что мы читаем два потока последовательно, а не одновременно. Чтобы избежать этого, нужно одновременно очищать и стандартный вывод, и ошибку. До сих пор у нас было два варианта:
1. Использовать асинхронные операции чтения для StandardOutput и StandardError
p.Start();
var outTask = p.StandardOutput.ReadToEndAsync();
var errTask = process.StandardError.ReadToEndAsync();
await Task.WhenAll(outTask, errTask, p.WaitForExitAsync());
var output = await outTask;
var error = await errTask;
2. Использовать события OutputDataReceived и ErrorDataReceived
События возникают при записи строки в stdout и stderr соответственно:
StringBuilder stdOut = new(), stdErr = new();
p.OutputDataReceived += (sender, e) => stdOut.AppendLine(e.Data);
p.ErrorDataReceived += (sender, e) => stdErr.AppendLine(e.Data);
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();
Существующие API не оптимальны с точки зрения простоты и производительности.
Продолжение следует…
Источник: https://devblogs.microsoft.com/dotnet/process-api-improvements-in-dotnet-11/
👍9