C# Portal | Программирование
13.9K subscribers
1.15K photos
126 videos
29 files
931 links
Присоединяйтесь к нашему каналу и погрузитесь в мир для C#-разработчика

Сотрудничество, реклама: @devmangx

Менеджер: @Spiral_Yuri

РКН: https://clck.ru/3FocB6
Download Telegram
Лучший конфиг для HttpClient это тот, который ты не копируешь в каждом сервисе.

В .NET ты настраиваешь все один раз через IHttpClientFactory (и Aspire, если используешь):

* service discovery для вызовов сервис-сервис
* дефолтную resiliency-настройку, чтобы кратковременные фейлы не ломали тебе жизнь

Дальше просто инжектишь клиент и пишешь бизнес-код.

- полный разбор

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👏6
25 Claude Code skills для .NET-разрабов

Покрывает штуки, которые реально важны и неочевидны (типа: как тестировать транзакционные письма в ASP.NET Core?) и вообще помогает улучшать вывод LLM (типы!).

github.com/Aaronontheweb/dotnet-skills?tab=readme-ov-file

Все это про то, чтобы Claude делал вещи нормально без того, чтобы ты на него орал.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍2🥴2
БОЛЬШОЙ SQL грех

Никогда не пихай ORDER BY внутрь CTE (или подзапроса), если там же рядом нет LIMIT.

Если LIMIT забыть, база обычно будет сортировать всю таблицу вообще без смысла.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍43👏2👎1
Как пользоваться LINQ

Чтобы использовать LINQ, нужно подключить System.Linq через using.

➡️ Фильтрация через Where

Если использовать Where, можно коротко вытащить из массива/списка только элементы, которые подходят под условие.
Результат вывода ниже будет 1.

// список int
List<int> idList = new List<int>{1, 2, 3};

// фильтруем: берём только те, где 1
IEnumerable<int> selectList = idList.Where(id => id == 1);


➡️ Цикл через ForEach

Если использовать ForEach, можно так же, как в обычном ForEach, сделать цикл короче, чем for.
Результат вывода ниже будет 1,2,3.

// список int
List<int> idList = new List<int>{1, 2, 3};

// проходимся по всему списку
idList.ForEach(id =>
{
print(id);
}


➡️Комбинации

LINQ при правильной комбинации может сильно сокращать код.
В примере ниже из attackList берутся элементы, где totalAttack != 0, затем они группируются по totalAttack, и группы сортируются по totalAttack.

// группировка по totalAttack (одинаковый totalAttack, разные GridInfo)
IEnumerable<IGrouping<int, GridInfo>> total = attackList
.Where(info => info.totalAttack != 0) // фильтруем где есть totalAttack
.GroupBy(info => info.totalAttack) // группируем по totalAttack
.OrderBy(group => group.Key); // сортируем по totalAttack


➡️Пошаговая обработка через Select

Select позволяет легко обработать элементы массива по порядку.
В коде ниже каждый элемент массива строк по одному конвертируется в int, а затем весь результат превращается в List<int>.
(В других языках это что-то вроде Map: берём элементы массива и преобразуем)

// массив String
string[] idString = {"1", "2", "3"};

// делаем int и превращаем в List
List<int> idList = idString.Select(id => int.Parse(id)).ToList();


➡️Any как OR-условие

Any возвращает true, если хотя бы один элемент удовлетворяет условию.
В коде ниже проверяем, есть ли в списке имён хотя бы одно, которое начинается с "A".

// List строк
List<string> names = new List<string> { "Alice", "Bob", "Charlie" };

// Alice подходит, значит True
names.Any(name => name.StartsWith("A"));


➡️ GetRange: взять диапазон элементов

GetRange позволяет взять из списка элементы по указанному диапазону.
В примере ниже при 0〜5 можно получить "1, 2, 3, 4", но если указать диапазон за пределами размера списка, будет ошибка.

// List int
List<int> idList = new List<int> { 1, 2, 3, 4, 5 };

// берём элементы 0〜4
idList.GetRange(0, 5);

// ошибка 1
idList.GetRange(0, 6);

// ошибка 2
idList.GetRange(1, 5);


➡️Reverse: развернуть список

Reverse разворачивает порядок элементов в списке.
В коде ниже изначально список "1, 2, 3, 4, 5", после Reverse станет "5, 4, 3, 2, 1".

// List int
List<int> idList = new List<int> { 1, 2, 3, 4, 5 };

// выводим 1〜5
idList.ForEach(id =>
{
print(id);
});

// разворот
idList.Reverse();

// выводим 5〜1
idList.ForEach(id =>
{
print(id);
});


➡️Single: получить единственный элемент

Single позволяет получить элемент, который встречается ровно один раз.
В коде ниже пытаемся через Where получить из списка "1, 1, 1, 1, 2" значения 2 и 1.
Для 2 всё ок (он один), а для 1 будет ошибка, потому что 1 встречается несколько раз.

// List int
List<int> idList = new List<int> { 1, 1, 1, 1, 2 };

// берём только 2
int select = idList.Where(id => 2).SingleOrDefault();

// ошибка
int select = idList.Where(id => 1).SingleOrDefault();


➡️Contains: проверить наличие элемента

Contains позволяет проверить, есть ли элемент в списке.
В коде ниже проверяем, есть ли в списке "Alice, Bob, Charlie" значение "Alice".

// List строк
List<string> names = new List<string> { "Alice", "Bob", "Charlie" };

// Alice есть в списке, значит True
names.Contains(name => name.StartsWith("Alice"));


👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🥰3
Фанфакт: в C# можно руками создать окно через Win32 API, прям как в C++.

По ощущениям это реально то же самое, что и в C++: регаешь window class, делаешь CreateWindowEx, заводишь WndProc, гоняешь GetMessage/DispatchMessage. Практической пользы почти ноль по сравнению с WinForms, но поиграться прикольно :D

Что в итоге получаешь: очень лёгкую штуку без лишнего оверхеда. Если использовать LibraryImport + NativeAOT (это быстрее и приятнее, чем классический P/Invoke), можно собрать примерно 1MB exe без DLL, который моментально стартует и открывает окно. Делать так в проде обычно незачем, это скорее чисто эксперимент.

И да, туда же спокойно добавляются кнопки и прочие контролы через тот же Win32. Выглядит олдскульно, но зато железобетонно понимаешь, как GUI под капотом работает.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔8👍43👎1🤯1
image_2026-01-30_09-10-14.png
796.9 KB
Шпора по C# для игр

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
😐32🥴5😁2🤯1🤨1
Два файла, которые я создаю еще до того, как напишу первую строку .NET-кода:

Directory.Packages.props и Directory.Build.props

Что это вообще такое?

Это файлы, которые ты добавляешь в solution, чтобы повысить сопровождаемость.

1/ Directory.Build.props

Этот файл централизует общие настройки проектов по всей solution.

версия .NET
nullable reference types
предупреждения компилятора
анализаторы

Вместо того чтобы копировать одну и ту же конфигурацию в каждый csproj, ты задаешь ее один раз.
Все проекты следуют одним правилам, поэтому со временем настройки не начинают “разъезжаться”.

2/ Directory.Packages.props

Этот файл управляет версиями NuGet-пакетов для всей solution.

Ты задаешь версии NuGet в одном месте, и все проекты используют именно их. В больших кодовых базах это убирает целый класс болезненных сюрпризов при сборках и деплоях.

Эти два файла особенно полезны при апгрейде версии .NET:

1. Меняешь в Directory.Build.props версию .NET.
2. Обновляешь версии пакетов в Directory.Packages.props.
3. Всё, готово.

Хочешь, чтобы .NET-решения нормально жили годами, начни с добавления этих двух простых файлов.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
30👍5🍌2
Поток выполнения запроса Entity Framework ⬇️
Please open Telegram to view this post
VIEW IN TELEGRAM
9👌4
Все еще сидишь на .sln в 2026?

Давай покажу, с чем ты реально имеешь дело:

Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApp", "MyApp\MyApp.csproj", "{8A3B4E29-7F7D-4C51-9A18-5D8B9A3E1234}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU

.... +200 more unreadable lines?


🤮Везде GUID’ы, вечные merge-конфликты, читать невозможно.

А теперь то же самое в .slnx:

<Solution>
<Project Path="MyApp/MyApp.csproj" />
</Solution>


Вот и всё. Читаемо человеком, дружит с git, никаких GUID’ов.

Почему стоит мигрировать сейчас:

▪️Поддерживается в Visual Studio 2022 (17.10+) и .NET 9+
▪️dotnet sln migrate делает это одной командой
▪️Меньше merge-конфликтов, меньше боли в команде
▪️В code review это наконец можно нормально читать

Как мигрировать:

dotnet sln migrate MyApp.sln


Готово. .slnx создан.

Старый формат делали под внутренности Visual Studio, не под людей. SLNX делают для разработчиков.

Все еще держишься за .sln? Почему?

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍284🔥1
Это markdown-док с практическими рекомендациями по асинхронщине в .NET и типичным граблям, особенно в вебе на ASP.NET Core: читать

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍84
Используй [] вместо Array.Empty в corelib ⬇️
Please open Telegram to view this post
VIEW IN TELEGRAM
13😐9👎1
Знаешь, что даже простая смена C# langversion может повлиять на производительность?

В C# 11 поменялась генерация кода для конверсии method group так, чтобы в некоторых случаях избегать аллокаций.

Пример:

[Benchmark]
public int Lambda()
{
Func<int> func = () => Method();
return func();
}

[Benchmark]
public int MethodGroup()
{
Func<int> func = Method;
return func();
}

static int Method() => 42;


на net4.8 при LangVersion C# 10 и ниже вариант с method group может создавать делегат (то есть аллоцировать) и из-за этого быть заметно медленнее. А при LangVersion C# 11+ компилятор меняет генерацию кода так, чтобы делегат кэшировался, и аллокации пропадают.

В C# 11 поменяли codegen, чтобы кэшировать конверсию method group

C# 10 и ниже (делегат создается на месте):

return new Func<int>((object)null, __methodptr(Method))();


C# 11 и выше (делегат кэшируется):

return (MethodGroupBenchmarks.<>O.<0>__Method ??
(MethodGroupBenchmarks.<>O.<0>__Method = new Func<int>((object)null, __methodptr(Method))))();


👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔8
В .NET 10 больше не нужно писать Dockerfile.
Кто уже пользуется новой фичей? Как ощущения в проде?

Типичный многостадийный Dockerfile для .NET-приложения выглядит примерно так:

FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
EXPOSE 8080
EXPOSE 8081

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["src/MyApi/MyApi.csproj", "src/MyApi/"]
RUN dotnet restore "src/MyApi/MyApi.csproj"

COPY . .
WORKDIR "/src/src/MyApi"
RUN dotnet build "MyApi.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "MyApi.csproj" -c $BUILD_CONFIGURATION -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyApi.dll"]


Это работает, но есть кривая обучения и накладные расходы на поддержку:

Поддержка: нужно вручную обновлять теги базовых образов
Кэширование слоёв: неправильный порядок COPY убивает кэш сборки
Дублирование: почти каждому проекту нужен похожий Dockerfile
Переключение контекста: ты пишешь Docker DSL, а не .NET-код

Подход с .NET SDK устраняет все эти проблемы.

Если ты работаешь на .NET 10, ничего дополнительно включать не нужно. Публикация в контейнеры работает из коробки для ASP.NET Core-приложений, worker-сервисов и консольных приложений.

Можно сразу публиковать приложение в контейнерный образ:

dotnet publish --os linux --arch x64 /t:PublishContainer


И всё. .NET SDK сам:

соберёт приложение
подберёт подходящий базовый образ
создаст контейнерный образ с результатом публикации
загрузит его в локальный OCI-совместимый демон

Чаще всего это Docker, но Podman тоже поддерживается.

(На скрине показан вывод команды dotnet publish, создающей контейнерный образ.)

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥146
This media is not supported in your browser
VIEW IN TELEGRAM
AviyalWM: портативный и лёгкий оконный менеджер, написанный на C#

Рад сообщить о релизе AviyalWM — простого, лёгкого и портативного динамического тайлингового оконного менеджера для Windows. Краткий список возможностей:

▪️Рабочие пространства
▪️Анимации рабочих пространств (горизонтальные и вертикальные)
▪️Макеты: Dwindle, Stack, Master
▪️Переключение в плавающий режим
▪️Закрытие окна в фокусе
▪️Переключение фокуса
▪️Конфигурация через JSON
▪️Горячая перезагрузка
▪️Запрос состояния через WebSocket и выполнение команд
▪️Запуск приложений с помощью горячих клавиш

Репозиторий: https://github.com/TheAjaykrishnanR/aviyal

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
12🔥2
В .NET теперь добавили DecompressionMethods.Zstandard для автоматической распаковки HTTP-ответов

Это изменение вчера влито в dotnet main и, судя по всему, будет доступно в .NET 11.

На втором фото есть таблица от Gemini с сравнением Gzip, Brotli и Zstandard по скорости и сжатию.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👏13🔥21
Расширение CSV/TSV Editor для Visual Studio

Mads из Microsoft только что выпустил это, и выглядит реально круто.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥62
Когда появился Docker, это была настоящая революция.

Теперь .NET Aspire меняет способ доставки ПО навсегда.

И многие разработчики до сих пор не осознают масштаб этого сдвига.

Docker решил хаос с окружениями

До Docker проблема «у меня работает» была ежедневной:
• Разные версии ОС
• Отсутствующие зависимости
• Сломанные окружения повсюду

Docker решил это, стандартизировав окружения через контейнеры.
Одна команда → одно и то же приложение, одинаковое поведение, везде.

Это действительно было революцией.

Но Docker не решил всё

Он пакует приложения, но связи между сервисами всё ещё настраиваются вручную:
• Всё ещё приходится управлять строками подключения
• Всё ещё самому настраивать наблюдаемость

И распределённые системы остаются сложными.

Здесь .NET Aspire меняет правила игры

Aspire — это слой оркестрации для современных приложений.

Что Aspire делает из коробки:
• Service discovery → никаких хардкодных URL или портов
• Injection конфигураций → базы данных и кеши подключаются автоматически
• Встроенная наблюдаемость → логи, метрики, трассировки, готово с первого дня
• Локальная оркестрация → запускаем всю систему одной командой
• Production-ready деплой → через Docker Compose
• Cloud-ready деплой → Azure или AWS

Вот сам гайд

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍6
Поддержка паролей для ZIP-архивов появится в .NET 11? 🙈

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🤯91🔥1
Вышел новый превью .NET для Microsoft Agent Framework! Обновлённые API, только асинхронные потоки и помощники AsAIAgent. Разбираем критические изменения, новые примеры с Durable Agents и ключевые обновления пакетов.

Подробнее: https://hubs.li/Q0410DQ-0

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥3👍21🔥1
Я очень долго не знал, что в Swagger есть такая фича. Даже не задумывался о ней до недавнего времени.

Совет:

if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
// подожди… он ЗАПОМИНАЕТ мой Bearer Token?!
// даже после полного обновления браузера…
c.EnablePersistAuthorization();

// на один клик меньше, на одно лишнее дёрганье мышью меньше
c.EnableTryItOutByDefault();
});
}


Если ты тоже об этом не знал, это вполне может сэкономить тебе немного времени!

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍244🤯2