C# Portal | Программирование
14.8K subscribers
895 photos
105 videos
24 files
749 links
Присоединяйтесь к нашему каналу и погрузитесь в мир для C#-разработчика

Связь: @devmangx

РКН: https://clck.ru/3FocB6
Download Telegram
В экосистеме ASP.NET Core появилась небольшая, но полезная утилита для управления консольным окном. Разработчик выложил на GitHub пример кода, который позволяет принудительно показать консоль для логирования и менять её заголовок по своему вкусу. Инструмент уже протестирован на Windows 11 и может пригодиться тем, кто пишет сервисы с дополнительным выводом в терминал.

Репозиторий с исходниками:
https://github.com/karenpayneoregon/csharp-basics-2025/blob/master/AspCoreHelperLibrary/WindowHelper.cs

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
1🤔1🥴1
В C# это довольно удобно: var завезли как раз тогда, когда добавили анонимные типы.

Хотя код тут чисто для демонстрации, забавно, что никто не заметил тупой баг на строке 4.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👎31
Rider 2025.3 Release Candidate уже доступен!

В этой сборке собраны все изменения и улучшения, которые будут в следующем крупном релизе. Попробуй и поделись впечатлениями о новых фичах и производительности Rider ;)

Подробнее и ссылка на скачивание тут : https://blog.jetbrains.com/dotnet/2025/11/05/the-rider-2025-3-release-candidate/

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
Добавляем Описание в Параметризованные Тесты

Часто нам требуется протестировать несколько вариантов использования метода с разными данными, и для этого подойдут параметризованные тесты, например, Theory в xUnit.

При этом бывает полезно добавить не только тестовые данные, но и описание к каждому тестовому случаю. Рассмотрим, как это сделать.

Представим, что у нас есть такой тест:

[Theory]
[MemberData(nameof(InvalidFilters))]
public async Task ShouldNotAllowInvalidInvariants(
LimitFilters filters)
{

}


Тест принимает следующую запись с тестовыми данными:

public record LimitFilters(
Guid? WorkpieceNumber,
IEnumerable<int>? Ids,
IEnumerable<int>? Tools,
IEnumerable<int>? LimitIds);
}


Если мы выполним тест, мы увидим в окне выполнения теста что-то вроде следующего:

ShouldNotAllowInvalidInvariants(filters: { WorkpieceNumber = … })
ShouldNotAllowInvalidInvariants(filters: { WorkpieceNumber = … })


Как видите, сложно понять, о чём каждый тестовый случай, особенно учитывая, что у нас есть коллекции в параметрах. Но обратите внимание, что из-за использования record, мы видим строковое представление записи, т.к. среда выполнения вызывает метод ToString() параметров. Мы можем использовать это.

Чтобы заставить среду выводить более осмысленное описание, мы можем добавить описание теста в LimitDesignerFilters и переопределить метод ToString():

public record LimitDesignerFilters(
string Description,
Guid? WorkpieceNumber,
IEnumerable<int>? Ids,
IEnumerable<int>? Tools,
IEnumerable<int>? LimitIds)
{
public override string ToString()
=> Description;
}


Теперь мы можем задать свойству Description описание каждого тестового случая:

public static TheoryData<LimitDesignerFilters> 
InvalidFilters =>
[
new("Workpiece is null", null, [1], [1], [1]),
new("Param1 is null", Guid.NewGuid(), null, [1], [1]),
];


Тогда в окне выполнения теста мы увидим следующее:

ShouldNotAllowInvalidInvariants(filters: Param1 is null)
ShouldNotAllowInvalidInvariants(filters: Workpiece is null)


Тут всё ещё присутствует название параметра (filters), но всё же, понять, что проверяет каждый тест, уже гораздо проще.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
8
В EF Core 10 (preview) появилась поддержка нескольких глобальных фильтров на одну сущность

Раньше в Entity Framework Core можно было задать только один HasQueryFilter для каждой сущности, что было неудобно, если нужно, например, одновременно фильтровать по IsDeleted и TenantId. Теперь в версии 10 это можно делать, но главное, дать каждому фильтру имя.

Пример:

modelBuilder.Entity<Blog>()
.HasQueryFilter("SoftDeletionFilter", b => !b.IsDeleted)
.HasQueryFilter("TenantFilter", b => b.TenantId == tenantId);


Теперь можно управлять каждым фильтром отдельно: включать, отключать или комбинировать как нужно.
Фича уже доступна в preview и обещает сильно упростить жизнь тем, кто работает с multi-tenant и soft delete сценариями.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
6🔥1
Небольшая деталь, но именно она делает работу с данными точной и предсказуемой

Не вызывай несколько OrderBy подряд. Каждый новый OrderBy пересортирует коллекцию заново и предыдущая сортировка пропадет. Для дополнительного критерия сортировки используй ThenBy.

Плохой вариант:

products
.OrderBy(x => x.Name)
.OrderBy(x => x.Price) // всё пересортирует по цене


Правильный вариант:

products
.OrderBy(x => x.Name)
.ThenBy(x => x.Price)


👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
17👍12
Скрипт PowerShell для переименования проектов .NET

Переименовать проект .NET - утомительное занятие. Вам придётся переименовать файлы и папки, а также заменить содержимое в файлах, например пространство имён или путь в файлах .sln.

Следующий скрипт PowerShell, переименует файлы и папки и заменит содержимое в файлах:

$ErrorActionPreference = "Stop"

$rootFolder = Resolve-Path -Path "."
$oldName = "SampleRazorPages"
$newName = "SampleWebApp"

# Переименовываем файлы и папки
foreach ($item in Get-ChildItem -LiteralPath $rootFolder -Recurse | Sort-Object -Property FullName -Descending) {
$itemNewName = $item.Name.Replace($oldName, $newName)
if ($item.Name -ne $itemNewName) {
Rename-Item -LiteralPath $item.FullName -NewName $itemNewName
}
}

# Заменяем содержимое в файлах
foreach ($item in Get-ChildItem $rootFolder -Recurse -Include "*.cmd", "*.cs", "*.csproj", "*.json", "*.md", "*.proj", "*.props", "*.ps1", "*.sln", "*.slnx", "*.targets", "*.txt", "*.vb", "*.vbproj", "*.xaml", "*.xml", "*.xproj", "*.yml", "*.yaml") {
$content = Get-Content -LiteralPath $item.FullName
if ($content) {
$newContent = $content.Replace($oldName, $newName)
Set-Content -LiteralPath $item.FullName -Value $newContent
}
}


👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20🔥2
Насколько зрел формат dotnet .slnx?

Видел этот вопрос на Reddit. Насколько я понимаю, формат уже готов к использованию. Кто-нибудь его уже применяет?

Пример нового формата .slnx для dotnet → на фото

Это старый скриншот (сейчас уже доступен в стабильной версии Visual Studio), но видно, что новый формат стал заметно менее многословным.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
7🤔5
Оптимизация roundtrip в Entity Framework 7

Хорошая оптимизация убирала лишние транзакции, если число вставляемых строк меньше или равно размеру батча 42 у провайдера SQL Server.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
3😁3🤔1
This media is not supported in your browser
VIEW IN TELEGRAM
Если вы когда-нибудь работали с базами данных, то знаете про LEFT JOIN (и, соответственно, RIGHT JOIN). Это одна из самых частых операций в SQL.
Но в Entity Framework Core реализовать левое соединение всегда было немного мучением.

Проблема старого LINQ


До .NET 10 в LINQ не было прямого способа выразить LEFT JOIN или RIGHT JOIN.
Вместо этого приходилось городить конструкцию через GroupJoin + DefaultIfEmpty, чтобы сохранить строки из левой таблицы даже при отсутствии совпадений.
Это работало, но выглядело громоздко и плохо читалось.

Пример (старый способ)

var query =
from product in dbContext.Products
join review in dbContext.Reviews on product.Id equals review.ProductId into reviewGroup
from subReview in reviewGroup.DefaultIfEmpty()
orderby product.Id, subReview.Id
select new
{
ProductId = product.Id,
product.Name,
product.Price,
ReviewId = (int?)subReview.Id ?? 0,
Rating = (int?)subReview.Rating ?? 0,
Comment = subReview.Comment ?? "N/A"
};


Генерируемый SQL:

SELECT
p."Id" AS "ProductId",
p."Name",
p."Price",
COALESCE(r."Id", 0) AS "ReviewId",
COALESCE(r."Rating", 0) AS "Rating",
COALESCE(r."Comment", 'N/A') AS "Comment"
FROM "Products" AS p
LEFT JOIN "Reviews" AS r ON p."Id" = r."ProductId"
ORDER BY p."Id", COALESCE(r."Id", 0)


Метод-синтаксис был ещё менее читаем — GroupJoin, SelectMany, DefaultIfEmpty и прочие танцы с бубном.

Новое в .NET 10: LeftJoin и RightJoin

Теперь в LINQ появились встроенные методы LeftJoin() и RightJoin(), которые наконец-то делают ровно то, что от них ожидаешь.
EF Core корректно транслирует их в SQL-запрос с LEFT JOIN или RIGHT JOIN.

Пример LeftJoin

var query = dbContext.Products
.LeftJoin(
dbContext.Reviews,
product => product.Id,
review => review.ProductId,
(product, review) => new
{
ProductId = product.Id,
product.Name,
product.Price,
ReviewId = (int?)review.Id ?? 0,
Rating = (int?)review.Rating ?? 0,
Comment = review.Comment ?? "N/A"
})
.OrderBy(x => x.ProductId)
.ThenBy(x => x.ReviewId);


Результирующий SQL тот же, что и раньше, но код стал в разы короче и понятнее.
Теперь сразу видно намерение: LeftJoin - значит левое соединение.

RightJoin

RightJoin делает обратное: сохраняет все строки из правой таблицы, добавляя данные из левой, если они есть.
EF Core транслирует это в RIGHT JOIN.

var query = dbContext.Reviews
.RightJoin(
dbContext.Products,
review => review.ProductId,
product => product.Id,
(review, product) => new
{
ProductId = product.Id,
product.Name,
product.Price,
ReviewId = (int?)review.Id ?? 0,
Rating = (int?)review.Rating ?? 0,
Comment = review.Comment ?? "N/A"
});


SQL:

SELECT
p."Id" AS "ProductId",
p."Name",
p."Price",
COALESCE(r."Id", 0) AS "ReviewId",
COALESCE(r."Rating", 0) AS "Rating",
COALESCE(r."Comment", 'N/A') AS "Comment"
FROM "Reviews" AS r
RIGHT JOIN "Products" AS p ON r."ProductId" = p."Id"


Несколько советов:

- В проекции защитите сторону, допускающую null: review.Comment ?? "N/A";
- Сохраняйте проекции небольшими, чтобы не извлекать больше столбцов, чем необходимо;
- Добавляйте индексы по ключам объединений для улучшения планов запросов.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥6
Краткое обновление по .NET 10 — версия готовится к выходу и приносит много интересного. Ниже главное, что удалось собрать.

Подтверждённые изменения:

Версия .NET 10 получит статус LTS (Long-Term Support) с поддержкой несколько лет.

Основные улучшения в рантайме: оптимизация JIT, улучшенная инлайнинг/де­виртуализация, улучшения для struct-аргументов.

Новое в C# 14: поддержка модификаторов параметров в лямбдах (ref, in, out), расширенные возможности field-ключевого слова, «extension blocks», null-conditional assignment и др.

В ASP.NET Core / Blazor: улучшения производительности, новые возможности для WebAssembly, улучшенная валидация форм и др.

Несколько оговорок:

Хотя вы могли увидеть сообщение «.NET 10 уже вышел сегодня», официальная GA-дата запланирована на 11 ноября 2025.
InfoQ

Сейчас доступны версии RC (Release Candidate) с поддержкой «go-live».

Не все анонсированные функции ещё подтверждены полностью либо ещё не вошли в стабильную версию.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
5🔥5👍4
This media is not supported in your browser
VIEW IN TELEGRAM
Понимай любую кодовую базу за секунды прямо в VS Code 🤯

Это расширение превращает весь твой проект в наглядную архитектурную визуализацию / показывает, как всё связано, двигается и зависит друг от друга.

Идеально, когда ты подключаешься к новому репозиторию или возвращаешься к старому.

Что делать:

1. Установи расширение Swark
2. Открой Command Palette (Ctrl + Shift + P)
3. Введи “Swark: Create Architecture Diagram” и выбери команду
4. Укажи корневую папку проекта

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
14🔥5👎1
.NET 10 уже вышел!

Вот главные обновления по ключевым направлениям:

C# 14
— расширяемые члены, свойства с полями, implicit spans и обновлённый nameof с поддержкой лямбд. Код стал чище и лаконичнее.

ASP.NET Core
— улучшенная поддержка OpenAPI, встроенная валидация для Minimal API, Server-Sent Events (SSE) и аутентификация с passkey.

EF Core
— добавлен поиск по векторам в SQL, улучшен LINQ–SQL перевод, появились Complex Types и полнотекстовый поиск в Cosmos DB.

Runtime
— прокачанный JIT-компилятор, больше stack allocation, поддержка AVX10.2 и улучшенный NativeAOT — приложения стали легче и быстрее.

Библиотеки
— новые криптографические API, свежие опции для JSON-сериализации, новый WebSocketStream API и ускоренная работа с ZipArchive.

SDK
— апдейты для file-based apps, поддержка контейнеров в консольных приложениях, tab-completion и команда dotnet tool exec.

Aspire
— полноценная поддержка Python и JS, деплой через Aspire Do, контейнеры как артефакты и новый AppHost CLI.

.NET MAUI
— улучшена диагностика и телеметрия верстки, добавлен XAML source generator, обновлён MediaPicker и шаблон Aspire service-defaults.


Нужна стартовая точка под .NET 10? Пора обновляться.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
18👍9👏2🥴1
Похоже, Entity Framework Core с .SqlQuery становится моим новым основным способом доступа к данным.

По моим неофициальным замерам, производительность выше, чем у Dapper, и при этом всё гораздо проще.

Чуть-чуть медленнее, чем чистый ADO.NET, но разница минимальная.
DbContext при этом остаётся максимально лёгким.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥18👍87
Extension members в C# 14, пожалуй, лучшее, что Microsoft добавила в язык. Теперь можно писать такой чистый и лаконичный код.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🥴29👍9🔥4🤔3👏1
Новая версия AsyncAwaitBestPractices v10.0.0

Добавлена поддержка .NET 10

Та самая библиотека async/await, которую все любят, теперь собрана и оптимизирована под .NET 10.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🥴7👍4🔥2
Оптимизация запроса в EF Core снизила время выполнения с 30 секунд до 30 миллисекунд.

Вот какие шаги помогли

Исходный запрос был из реального проекта соцсети.

Сущности и связи:

Users — у каждого много постов и комментариев

Comments — привязаны к юзеру и посту

Categories — у постов есть категория

Posts — имеют категорию и множество лайков

Likes — относятся к конкретному посту

Задача:

Выбрать топ 5 пользователей, которые оставили больше всего комментариев за последние 7 дней под постами категории .NET.

Для каждого нужно вернуть:

- UserId
- Username
- количество комментариев (только под .NET постами за последние 7 дней)
- топ 3 .NET поста по лайкам, которые этот пользователь чаще всего комментировал (PostId, LikesCount)

Что было сделано для ускорения:

- Предфильтрация пользователей
- Ограничение до топ-5
- Сокращение числа JOIN
- Проекция только нужных полей
- Формирование результата в одном запросе
- Использование AsSplitQuery
- Трехфазный подход
- Двухфазный подход

Подробности можно посмотреть здесь

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🥴104👍2😁1
Media is too big
VIEW IN TELEGRAM
WinForms приложения на .NET Framework можно переехать в web на .NET 9+ и задеплоить в Azure App Services через Visual Studio и copilot за пару минут.

Вся логика приложения и бизнес-код сохраняются.
Сочетание Visual Studio 2026 и GitHub Copilot творит вещи.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯15🥴4🤔3👍2