Улучшения по производительности таймзон в dotnet 11
В .NET 11 добавили кэш переходов таймзон по годам (per-year cache) для
По бенчмаркам ускорение такое:
▪️ Windows: примерно в 2.4–3.9 раза быстрее (например,
▪️ Linux: примерно в 1.6–4.7 раза быстрее (например,
Плюс новый путь с кэшем заменил старую “слоеную” логику конвертации (которую годами патчили) и заодно поправил несколько багов, где конвертация могла давать неправильный результат.
👉 @KodBlog
В .NET 11 добавили кэш переходов таймзон по годам (per-year cache) для
TimeZoneInfo, из-за чего конвертация времени стала заметно быстрее. Кэш хранит все переходы за конкретный год в UTC и убирает повторные lookup-и правил при каждом пересчете. По бенчмаркам ускорение такое:
ConvertTimeFromUtc с 48.0 нс до 12.2 нс) ConvertTimeToUtc с 63.8 нс до 13.6 нс) Плюс новый путь с кэшем заменил старую “слоеную” логику конвертации (которую годами патчили) и заодно поправил несколько багов, где конвертация могла давать неправильный результат.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3❤2👍1
Твой GET-эндпоинт возвращает все строки из таблицы. На 100 записей ок. На 100К это уже катастрофа.
3 вещи, которые нужны любому list-эндпоинту в .NET:
- Пагинация (
- Динамическая сортировка (по нескольким колонкам)
- Поиск (без учета регистра)
И все это одним SQL-запросом через EF Core 10.
https://codewithmukesh.com/blog/pagination-sorting-searching-aspnet-core-webapi/
👉 @KodBlog
3 вещи, которые нужны любому list-эндпоинту в .NET:
- Пагинация (
Skip + Take)- Динамическая сортировка (по нескольким колонкам)
- Поиск (без учета регистра)
И все это одним SQL-запросом через EF Core 10.
https://codewithmukesh.com/blog/pagination-sorting-searching-aspnet-core-webapi/
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯6👍3
Два варианта N+1 в Entity Framework.
👉 @KodBlog
// ================================
// ПРОБЛЕМА N+1 — ВАРИАНТ 1
// Ленивый (Lazy) loading навигационного свойства
// (в EF Core Lazy Loading по умолчанию ВЫКЛЮЧЕН)
// ================================
//
// Что происходит:
// - 1 запрос загружает всех пользователей
// - Затем КАЖДОЕ обращение к user.Orders автоматически триггерит отдельный запрос
// - Итого = 1 + N запросов
var users = context.Users.ToList(); // Запрос #1
foreach (var user in users)
{
// Запрос #2, #3, #4... #N+1 (по одному на пользователя, триггерится автоматически)
var orders = user.Orders.ToList();
}
// ================================
// ПРОБЛЕМА N+1 — ВАРИАНТ 2
// Явный запрос к дочерним данным внутри цикла
// ================================
//
// Что происходит:
// - 1 запрос загружает всех пользователей
// - Затем КАЖДАЯ итерация выполняет отдельный запрос за заказами этого пользователя
// - Итого = 1 + N запросов
var users2 = context.Users.ToList(); // Запрос #1
foreach (var user in users2)
{
// Запрос #2, #3, #4... #N+1 (по одному на пользователя)
var orders = context.Orders
.Where(o => o.UserId == user.Id)
.ToList();
}
Please open Telegram to view this post
VIEW IN TELEGRAM
😐15❤1👍1
Как заставить правила по данным применяться к КАЖДОМУ запросу, не копипастя одно и то же?
Global Query Filters в EF Core. Что важно знать:
1. Определяешь фильтр один раз в OnModelCreating, и EF Core сам добавляет WHERE ко всем запросам
2. Soft delete: HasQueryFilter(p => !p.IsDeleted) прячет удаленные записи без физического удаления
3. Multi-tenancy: ссылайся на поле DbContext для динамической фильтрации по tenant, запросы будут параметризованные
4. Named Filters (EF Core 10): можно задать НЕСКОЛЬКО фильтров на одну сущность и отключать их независимо
5. IgnoreQueryFilters(["SoftDelete"]): выключаешь ОДИН фильтр, остальные остаются активными
6. Паттерн с интерфейсом ISoftDelete: применяешь фильтры ко ВСЕМ сущностям, которые реализуют интерфейс, через expression trees
7. Индексируй колонки, по которым фильтруешь: IsDeleted и TenantId должны быть с индексами, потому что фильтры срабатывают на каждом запросе
👉 @KodBlog
Global Query Filters в EF Core. Что важно знать:
1. Определяешь фильтр один раз в OnModelCreating, и EF Core сам добавляет WHERE ко всем запросам
2. Soft delete: HasQueryFilter(p => !p.IsDeleted) прячет удаленные записи без физического удаления
3. Multi-tenancy: ссылайся на поле DbContext для динамической фильтрации по tenant, запросы будут параметризованные
4. Named Filters (EF Core 10): можно задать НЕСКОЛЬКО фильтров на одну сущность и отключать их независимо
5. IgnoreQueryFilters(["SoftDelete"]): выключаешь ОДИН фильтр, остальные остаются активными
6. Паттерн с интерфейсом ISoftDelete: применяешь фильтры ко ВСЕМ сущностям, которые реализуют интерфейс, через expression trees
7. Индексируй колонки, по которым фильтруешь: IsDeleted и TenantId должны быть с индексами, потому что фильтры срабатывают на каждом запросе
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🤔2❤1
Как маппить параметры query string в Minimal APIs?
(и простые, и сложные)
Query-параметры это опциональная часть URL, которую можно использовать, чтобы фильтровать или менять ответ в зависимости от переданных значений.
В Minimal APIs это делается довольно просто.
Minimal APIs поддерживают два типа query string параметров:
▪️ Простые
▪️ Сложные
Для простых параметров тебе достаточно, чтобы имена совпадали.
Для сложных типов нужно использовать атрибут
Начиная с .NET 7 также появилась поддержка массивов в query-параметрах.
👉 @KodBlog
(и простые, и сложные)
Query-параметры это опциональная часть URL, которую можно использовать, чтобы фильтровать или менять ответ в зависимости от переданных значений.
В Minimal APIs это делается довольно просто.
Minimal APIs поддерживают два типа query string параметров:
Для простых параметров тебе достаточно, чтобы имена совпадали.
Для сложных типов нужно использовать атрибут
[AsParameters], он замаппит свойства из запроса на класс.Начиная с .NET 7 также появилась поддержка массивов в query-параметрах.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5🤔1
Я много лет писал в проде и горизонтальный C#, и вертикальный. В итоге пришел вот к чему.
Горизонтальный стиль:
- Пишется быстрее
- Выглядит плотным и типа профессиональным
- Норм для совсем простых выражений
- После 100+ символов превращается в кашу
- Отлично прячет баги на виду (я лично пропустил 3 ошибки с неправильными аргументами в горизонтальном коде)
Вертикальный стиль:
- Занимает на пару секунд больше
- Выглядит слишком очевидно, прям до простоты
- Каждая операция читается отдельно, без напряга
- Дифы чище (одно изменение = одна строка в git)
- Ревью реально ускоряется
Мой дефолт: вертикально. Всегда. Но переключаюсь на горизонтальный, когда выражение реально простое: null-coalesce, базовый ternary, один метод в LINQ.
Правило, по которому решаю: если мне нужно провести глазами по строке горизонтально больше одного раза, значит надо делать вертикально.
Это не теория. Мы перелопатили 100+ .NET сервисов и сравнили время ревью PR до и после. В среднем ревью стало быстрее примерно на 30% после того, как ввели вертикальные стандарты форматирования.
👉 @KodBlog
Горизонтальный стиль:
- Пишется быстрее
- Выглядит плотным и типа профессиональным
- Норм для совсем простых выражений
- После 100+ символов превращается в кашу
- Отлично прячет баги на виду (я лично пропустил 3 ошибки с неправильными аргументами в горизонтальном коде)
Вертикальный стиль:
- Занимает на пару секунд больше
- Выглядит слишком очевидно, прям до простоты
- Каждая операция читается отдельно, без напряга
- Дифы чище (одно изменение = одна строка в git)
- Ревью реально ускоряется
Мой дефолт: вертикально. Всегда. Но переключаюсь на горизонтальный, когда выражение реально простое: null-coalesce, базовый ternary, один метод в LINQ.
Правило, по которому решаю: если мне нужно провести глазами по строке горизонтально больше одного раза, значит надо делать вертикально.
Это не теория. Мы перелопатили 100+ .NET сервисов и сравнили время ревью PR до и после. В среднем ревью стало быстрее примерно на 30% после того, как ввели вертикальные стандарты форматирования.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19❤4
Lazy Loading по умолчанию выключен в Entity Framework (Core), так что тебе реально нужно целенаправленно включать и искать вот этот вариант N+1 ⬇️
👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🥴3
Делегаты без накладных расходов в .NET 10
JIT в .NET 10 в некоторых случаях может полностью убрать стоимость абстракции при использовании делегатов.
👉 @KodBlog
JIT в .NET 10 в некоторых случаях может полностью убрать стоимость абстракции при использовании делегатов.
Enumerable.Any может быть таким же эффективным, как вручную написанный цикл, который достает Span из ListPlease open Telegram to view this post
VIEW IN TELEGRAM
🔥7❤1
Новый
И ты будешь им пользоваться. Звучит стремно, да?
Но тут другая история.
Официально продвигаемое предложение для C# 15 добавляет labeled
Это решает проблему, на которую все натыкаются в вложенных циклах.
И обычно мы решаем ее криво:
- Используем
- Заводим флаги, которые “протекают” состоянием и прячут намерение.
Оба варианта делают код хуже для чтения и поддержки.
А теперь представь так:
→ Ты задаешь имя циклу, из которого хочешь выйти.
→ Потом пишешь ровно то, что имеешь в виду.
“Выйти из внешнего цикла.”
“Продолжить внешний цикл.”
И да, в других языках это уже есть:
→ Java, Kotlin, Rust, Go, Swift.
C# наконец догоняет. Эту фичу просили годами.
Сейчас она уже официально поддержана (championed), а значит, очень вероятно, что она действительно доедет.
И когда доедет, ты будешь ее использовать.
Не потому что это обязательно. А потому что так просто лучше.
Лично мне идея нравится. А тебе как эта фича в C#?🚬
👉 @KodBlog
goto может появиться в C# 15И ты будешь им пользоваться. Звучит стремно, да?
Но тут другая история.
Официально продвигаемое предложение для C# 15 добавляет labeled
break и continue.Это решает проблему, на которую все натыкаются в вложенных циклах.
И обычно мы решаем ее криво:
- Используем
goto со странными метками где-то внизу цикла.- Заводим флаги, которые “протекают” состоянием и прячут намерение.
Оба варианта делают код хуже для чтения и поддержки.
А теперь представь так:
→ Ты задаешь имя циклу, из которого хочешь выйти.
→ Потом пишешь ровно то, что имеешь в виду.
“Выйти из внешнего цикла.”
“Продолжить внешний цикл.”
И да, в других языках это уже есть:
→ Java, Kotlin, Rust, Go, Swift.
C# наконец догоняет. Эту фичу просили годами.
Сейчас она уже официально поддержана (championed), а значит, очень вероятно, что она действительно доедет.
И когда доедет, ты будешь ее использовать.
Не потому что это обязательно. А потому что так просто лучше.
Лично мне идея нравится. А тебе как эта фича в C#?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍37❤7👎6
C# Primary Constructor пример:
👉 @KodBlog
// ДО .NET 8 (традиционный подход с конструктором)
public class UserService
{
private readonly HospitalDBContext _dbContext;
private readonly ILogger<UserService> _logger;
private readonly IEmailService _emailService;
public UserService(
HospitalDBContext dbContext,
ILogger<UserService> logger,
IEmailService emailService)
{
_dbContext = dbContext;
_logger = logger;
_emailService = emailService;
}
// Методы бизнес-логики здесь...
}
// ПОСЛЕ .NET 8 (с использованием первичного конструктора)
public class UserService(
HospitalDBContext _dbContext,
ILogger<UserService> _logger,
IEmailService _emailService)
{
// Методы бизнес-логики здесь...
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
CQS и CQRS часто путают.
CQS = Command Query Separation
Это про дизайн классов: метод либо меняет состояние , либо возвращает значение
CQRS = Command Query Responsibility Segregation
CQRS логически разделяет потоки чтения и потоки записи данных. Хотя это не взаимоисключающие вещи, CQRS можно воспринимать как более строгую версию CQS.
👉 @KodBlog
CQS = Command Query Separation
Это про дизайн классов: метод либо меняет состояние , либо возвращает значение
CQRS = Command Query Responsibility Segregation
CQRS логически разделяет потоки чтения и потоки записи данных. Хотя это не взаимоисключающие вещи, CQRS можно воспринимать как более строгую версию CQS.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Это довольно приятное улучшение в Visual Studio.
Строки, состоящие только из пробелов, а также строки, где только скобки или знаки пунктуации, можно отображать меньшим шрифтом. Это немного возвращает вертикальное пространство и заодно снижает визуальный шум.
Эту настройку можно найти здесь:
Options -> Text Editor -> Advanced -> Compress Blank Lines
👉 @KodBlog
Строки, состоящие только из пробелов, а также строки, где только скобки или знаки пунктуации, можно отображать меньшим шрифтом. Это немного возвращает вертикальное пространство и заодно снижает визуальный шум.
Эту настройку можно найти здесь:
Options -> Text Editor -> Advanced -> Compress Blank Lines
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15❤2🥴2🤔1
Только что словил неприятный нюанс в
На Windows по умолчанию используется
Итог: для директорий никогда не используйте *.*, если только вы явно не ищете папки, в имени которых есть ..
Раньше я всегда использовал *.*, что, вероятно, на самом деле никогда не было корректным вариантом, но это работало и возвращало все папки при MatchType.Win32.
👉 @KodBlog
GetDirectories: когда ты явно передаешь EnumerationOptions, режим по умолчанию становится Simple.На Windows по умолчанию используется
Win32, когда запускаешь без этого, из-за чего старый синтаксис *.* начинает ломатьсяИтог: для директорий никогда не используйте *.*, если только вы явно не ищете папки, в имени которых есть ..
Раньше я всегда использовал *.*, что, вероятно, на самом деле никогда не было корректным вариантом, но это работало и возвращало все папки при MatchType.Win32.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Blazor Minimum Project Templates v11.0.100-preview.1 получили поддержку таргета net11.0.
Если хочется стартовать с максимально чистого Blazor-шаблона, это как раз тот случай: без JS, без CSS-библиотек, с упором на чистый C#.
Можно ставить и пробовать уже сейчас для .NET 11 preview.
https://github.com/jsakamoto/BlazorMinimumTemplates
👉 @KodBlog
Если хочется стартовать с максимально чистого Blazor-шаблона, это как раз тот случай: без JS, без CSS-библиотек, с упором на чистый C#.
Можно ставить и пробовать уже сейчас для .NET 11 preview.
https://github.com/jsakamoto/BlazorMinimumTemplates
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤1
Чувак сделал намеренно уязвимое dotnet приложение 👀
Многие советы по безопасности в .NET остаются слишком абстрактными, пока ты не увидишь баг прямо в коде.
Поэтому этот проект, где всё намеренно сделано неправильно. Это намеренно уязвимое .NET-приложение, в котором собрано более 50 распространённых реальных ошибок, которые могут проскочить в обычный бизнес-код.
Ссылка - https://github.com/AlexGoOn/the-most-vulnerable-dotnet-app
Некоторые из включённых вещей:
👉 @KodBlog
Многие советы по безопасности в .NET остаются слишком абстрактными, пока ты не увидишь баг прямо в коде.
Поэтому этот проект, где всё намеренно сделано неправильно. Это намеренно уязвимое .NET-приложение, в котором собрано более 50 распространённых реальных ошибок, которые могут проскочить в обычный бизнес-код.
Ссылка - https://github.com/AlexGoOn/the-most-vulnerable-dotnet-app
Некоторые из включённых вещей:
Инъекционные атаки (SQL, command, template, LDAP, XML, logs)
Cross-Site Scripting (stored, reflected, в атрибутах, в SVG)
Небезопасная загрузка файлов (path traversal, Zip Slip, произвольная запись файлов)
Проблемы с криптографией (hashing, ECB, предсказуемый random)
Сериализация (XXE, XML bomb, binary, YAML)
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍3🤔1