C# 1001 notes
6.68K subscribers
415 photos
14 videos
2 files
368 links
Регулярные короткие заметки по C# и .NET.

Просто о сложном для каждого.

admin - @haarrp
Download Telegram
Эта задача проверяет понимание Memory<T>, pooling, ownership, IAsyncEnumerable, cancellation и одной из самых неприятных категорий ошибок высокопроизводительного C# — когда GC защищает объект от удаления, но не защищает вас от повторного использования его содержимого.
🧩 C# Channels: сообщение попало в очередь. Почему обработчик его не получил?

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


using System.Threading.Channels;

var queue = Channel.CreateBounded<int>(
new BoundedChannelOptions(1)
{
FullMode = BoundedChannelFullMode.Wait
});

using var cts = new CancellationTokenSource();

var firstRead = queue.Reader.ReadAsync().AsTask();

var firstWorker = Task.Run(async () =>
{
try
{
var item = await firstRead.WaitAsync(cts.Token);
Console.WriteLine($"A: {item}");
}
catch (OperationCanceledException)
{
Console.WriteLine("A: canceled");
}
});

// Дожидаемся, чтобы первый воркер обработал отмену.
cts.Cancel();
await firstWorker;

var secondWorker = Task.Run(async () =>
{
await foreach (var item in queue.Reader.ReadAllAsync())
Console.WriteLine($"B: {item}");
});

await queue.Writer.WriteAsync(42);
queue.Writer.TryComplete();

await secondWorker;
await queue.Reader.Completion;

Console.WriteLine("Finished");


Разберите без запуска:

1. Что выведет программа? Возможны ли разные результаты?
2. Где окажется 42, если ни один воркер его не напечатает?
3. Почему Reader.Completion успешно завершится?
4. Чем отличаются эти две записи?


reader.ReadAsync().AsTask().WaitAsync(token)
reader.ReadAsync(token).AsTask()


Усложнение: отмена и запись происходят одновременно. Достаточно ли второй записи, чтобы гарантировать, что сообщение не потеряется?

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

👇 В какой момент ответственность за сообщение переходит от канала к воркеру?
Ваш .NET API работает локально. Готов ли он к продакшену?

Чек-лист из 8 проверок перед релизом. Он посвящён решениям, которые позже влияют на поиск ошибок, поддержку API и внесение изменений. Удобно пройтись по нему перед выкладкой, даже если все эндпоинты уже отвечают как надо.

Читать статью - https://mwaseemzakir.substack.com/p/before-your-net-api-goes-to-production

#aspnetcore #dotnet
«Ядро Windows NT во многом превосходит Linux», считает исследовательница Google и бывший реверс-инженер Microsoft Лори Кирк.

Её аргумент касается устройства системы: в NT ресурсы представлены объектами с правами доступа. В Linux контроль строится из нескольких механизмов, включая права файлов, ACL, capabilities и SELinux. По мнению Кирк, из-за этого труднее ответить на вопрос: что именно разрешено ИИ-агенту, которому дали доступ к системе?

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

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

Источник: https://www.windowslatest.com/2026/09/26/google-researcher-explains-why-windows-nt-puts-linux-to-shame-and-imagines-an-alternate-history-where-it-won/
Задачка по C# 14: сколько раз вызовется Next()?


int calls = 0;
int Next() => ++calls;

Box? a = null;
Box b = new();

a?.Value = Next();
b?.Value = Next();
a?.Value += Next();
b?.Value += Next();

Console.WriteLine($"{calls} {b.Value}");

class Box
{
public int Value
{
get;
set => field = value * 10;
}
}


Варианты:


A) 4 120
😎 2 120
C) 2 30
D) Код не скомпилируется


Ответ: B) 2 120

Здесь сразу две фичи C# 14.

Первая: null-conditional assignment. Теперь
?. можно ставить слева от присваивания, в том числе составного. Главный подвох в том, что если объект слева равен null, правая часть вообще не вычисляется. Поэтому для a функция Next() ни разу не вызывается, и счётчик доходит только до 2, хотя вызовов в коде четыре.

Вторая: ключевое слово `field`. Геттер остаётся автоматическим, а сеттер умножает значение на 10, обращаясь к скрытому полю без ручного объявления.

Считаем по шагам:

```
b?.Value = Next() → Next() = 1, сохраняем 1 * 10 = 10
b?.Value += Next() → читаем 10, Next() = 2, 10 + 2 = 12, сохраняем 120
```

Бонусный подвох:
b?.Value++ уже не скомпилируется. Составное присваивание с ?. разрешено, а инкремент и декремент нет.
🔐 Как аутентифицировать SSE в ASP.NET Core?

SSE работает поверх обычного HTTP и поддерживает аутентификацию. Подвох в браузерном `EventSource`: он не позволяет задать заголовок Authorization.

В статье Paul Karam разобраны варианты:

• Cookies: браузер отправляет их автоматически для своего origin. Для другого нужны withCredentials: true и корректный CORS.
• Одноразовый короткоживущий токен в URL: при переподключении придётся получить новый.
• `@microsoft/fetch-event-source`: позволяет передать Bearer-токен в заголовке.
• `HttpClient`: вариант для .NET-клиентов с обычными заголовками аутентификации.

Долгоживущий access token в URL может утечь через логи сервера или прокси. На сервере SSE-эндпоинт защищается стандартными средствами ASP.NET Core, например .RequireAuthorization() при cookie-аутентификации.

https://tiger4589.github.io/2026/10/02/sse-with-authentication.html
🔐 Passkeys можно использовать как второй фактор в ASP.NET Core.

Пользователь вводит пароль, затем подтверждает вход через Touch ID, Windows Hello или аппаратный ключ. Без SMS и шестизначных кодов.

Маартен Баллиау показал реализацию на ASP.NET Core Identity в .NET 10: провайдер второго фактора, временная cookie и два эндпоинта для запроса и проверки passkey.

Есть важный нюанс: `PasskeySignInAsync()` выполняет прямой вход и обходит отдельный этап 2FA. Поэтому в таком сценарии нужно проверить, что passkey принадлежит именно пользователю, который уже прошёл проверку пароля.

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

https://blog.maartenballiauw.be/posts/2026-10-01-using-aspnet-core-passkeys-for-second-factor-authentication/
Forwarded from C# (C Sharp) programming
Helm-чарты прямо из C#, без запуска `helm` 🛠

HelmSharp позволяет рендерить шаблоны и управлять релизами Kubernetes внутри .NET-приложения.

Что умеет:

• Загружать чарты из папки и .tgz.
• Объединять values.yaml с пользовательскими параметрами.
• Упаковывать чарты и работать с HTTP-репозиториями.
• Устанавливать, обновлять, откатывать и удалять релизы.
• Хранить историю релизов в Kubernetes Secrets, совместимых с Helm v3.

Для начала:


dotnet add package HelmSharp.Action


Поддерживает .NET 8, 9 и 10, лицензия MIT.

Пригодится для собственных панелей управления и сервисов деплоя на C#. Совместимость с Helm пока частичная: свои чарты стоит проверить, особенно если они используют сложные шаблонные функции или расширения.

https://github.com/GaTTGeng/HelmSharp
🛠 У .NET появился свой аналог rustup и nvm

Microsoft представила dotnetup: менеджер для установки и обновления .NET SDK и рантаймов. Пока в публичном превью.

Всё устанавливается в папку пользователя, без sudo и прав администратора. Можно держать стабильные версии, превью и ежедневные сборки рядом, а закрепление SDK через global.json сохраняется.

Несколько полезных команд:


dotnetup init # Настроить окружение
dotnetup list # Показать установленные версии
dotnetup update # Обновить отслеживаемые версии
dotnetup sdk install preview # Установить превью SDK


Можно отслеживать обновления внутри конкретной ветки или закрепить точную версию. При обновлении ненужные компоненты очищаются автоматически.

https://devblogs.microsoft.com/dotnet/introducing-dotnetup/
В C# наконец появились union-типы

Разбираем C# 15 и .NET 11: union-типы, закрытые иерархии через closed, аргументы в коллекционных выражениях, extension-индексаторы и именованные break и continue.

Разработчики на C# просили размеченные объединения (discriminated unions) почти десять лет. Обсуждение в репозитории языка годами оставалось одним из самых популярных, а команды тем временем писали свои OneOf, Result и иерархии из абстрактных record с бесконечными default: throw. В C# 15, который выходит вместе с .NET 11, союзы наконец становятся частью языка. Вместе с ними приходят закрытые иерархии, аргументы в коллекционных выражениях, extension-индексаторы и именованные break/continue. Разберём, что из этого реально пригодится в коде уже сейчас.

https://uproger.com/csharp-15-union-types/
CBOR в .NET – компактный бинарный формат для случаев, когда JSON становится слишком расточительным.

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

Формат сам описывает типы значений: для чтения не требуется заранее согласованный `.proto`-файл, как у Protobuf.

В .NET используется пакет:


dotnet add package System.Formats.Cbor


Запишем аналог {"age":8}:


using System.Formats.Cbor;

var writer = new CborWriter();
writer.WriteStartMap(1);
writer.WriteTextString("age");
writer.WriteInt32(8);
writer.WriteEndMap();

byte[] data = writer.Encode();
Console.WriteLine(Convert.ToHexString(data));
// A16361676508


6 байт вместо 9 байт JSON в UTF-8. Выигрыш зависит от данных: для текста разница может быть небольшой.

Обратное чтение:


var reader = new CborReader(data);
reader.ReadStartMap();
string key = reader.ReadTextString();
int age = reader.ReadInt32();
reader.ReadEndMap();


Подвох: System.Formats.Cbor предоставляет низкоуровневые reader/writer API. Автоматической сериализации произвольных объектов через Serialize<T>() здесь нет.

Эндрю Лок разбирает устройство формата, сравнение с JSON и Protobuf и пример его использования внутри ASP.NET Core.

https://andrewlock.net/an-introduction-to-compact-binary-object-notation-in-dotnet/
Microsoft экстренно обновила .NET. Предыдущие патчи закрыли уязвимости не полностью

Microsoft выпустила внеплановые обновления безопасности для .NET 8, 9, 10 и 11 RC3. Причина - несколько уязвимостей, включая опасную ошибку при распаковке Brotli.

Что обнаружили:

- CVE-2026-111497 - переполнение буфера в Brotli. Злоумышленник потенциально может читать или повреждать память процесса, вызывать сбои и повышать привилегии.
- CVE-2026-114148 - небезопасные права владения файлами в Linux-дистрибутивах .NET.
- CVE-2026-70197 - повреждение памяти при работе с SocketAsyncEventArgs.
- CVE-2026-102870 - уязвимость отладчика Blazor WebAssembly.

Последние две особенно интересны: патчи от 13 октября не устранили проблемы полностью. Microsoft пришлось выпускать исправления повторно.

Обновлённые версии:

- .NET 8 → 8.0.33
- .NET 9 → 9.0.22
- .NET 10 → 10.0.14
- .NET 11 → RC3

Проверить установленный runtime:


dotnet --list-runtimes


Нюанс для DevOps: если приложение опубликовано как self-contained или работает в Docker, обновления runtime на хосте недостаточно. Потребуется пересборка и повторный деплой.

Особое внимание приложениям, которые обрабатывают недоверенные Brotli-сжатые данные через ASP.NET Core, HttpClient или System.IO.Compression.

https://devblogs.microsoft.com/dotnet/dotnet-october-2026-oob-security-updates/
Microsoft представит .NET 11 уже 10 ноября

С 10 по 13 ноября пройдёт .NET Conf 2026, бесплатная онлайн-конференция, приуроченная к выходу .NET 11.

Разработчики Microsoft расскажут, что изменилось в новой версии платформы, и покажут возможности обновлённого стека.

В программе C# 15, ASP.NET Core, Blazor, .NET MAUI, интеграция ИИ в .NET-приложения и обновления Visual Studio.

Будут технические доклады от команд Microsoft, демонстрации новых возможностей и выступления разработчиков из сообщества.

Участие бесплатное, всё проходит онлайн. Хорошая возможность разобраться в .NET 11 непосредственно с инженерами, которые его разрабатывают.

10–13 ноября 2026 года.

Программа и регистрация: https://devblogs.microsoft.com/dotnet/get-ready-for-dotnet-conf-2026/