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

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

Менеджер: @Spiral_Yuri

РКН: https://clck.ru/3FocB6
Download Telegram
Я очень долго не знал, что в 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
Перестаньте использовать булевые параметры.

user.SetStatus(true)

Когда читаешь такой код, приходится останавливаться и думать.
Что значит true? Активен? Подтверждён? Удалён?

Это называется flag argument.
Он заставляет лезть в определение метода, чтобы понять намерение.

Решение: заменяйте размытые булевые значения явными методами.
Вместо SetStatus(true) используйте user.Activate().

Намерение очевидно.
Язык читается естественно.
Комментарии не нужны.

Код читают намного чаще, чем пишут.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍164👎1
Деплой и апгрейд сервисов это всегда риск. В этом посте разбираем, как этот риск снижать.

Диаграмма выше показывает самые частые подходы.

▪️Multi-Service Deployment

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

▪️Blue-Green Deployment

В blue-green деплое есть две одинаковые среды: одна staging (blue), другая production (green). Staging на одну версию впереди прода. Когда тесты в staging пройдены, пользовательский трафик переключается на staging, и staging становится продом. У этой стратегии простой rollback, но держать две одинаковые прод-качества среды может быть дорого.

▪️Canary Deployment

Canary-деплой обновляет сервисы постепенно, каждый раз только для части пользователей. Это дешевле, чем blue-green, и откатываться тоже удобно. Но так как staging-среды нет, тестировать приходится на проде. Процесс сложнее, потому что нужно мониторить canary и шаг за шагом переводить все больше пользователей со старой версии на новую.

▪️A/B Test

В A/B тесте разные версии сервисов одновременно крутятся в проде. Каждая версия проводит “эксперимент” на своей доле пользователей. Это дешевый способ проверять новые фичи в проде. При этом нужно жестко контролировать деплой, чтобы какие-то фичи случайно не уехали пользователям.

Твой ход: какую стратегию деплоя ты использовал? Были ли у тебя продовые инциденты из-за деплоя, и почему они случились?

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥31
Что мне реально нравится в C#

Это не какая-то огромная или супер-впечатляющая фича, но мне заходит вот такое:

if (element is { Name: "tileset" })
{
...
}


Наверное потому что это близко к C и ассемблеру, поэтому такие штуки мне особенно кайфовые :-D

Почти всегда лучше дать компилятору сделать свою работу: он оптимизирует лучше, чем мы руками. Поэтому такие фичи и полезны.

Трюк и самая сложная часть для разработчика это понимать, когда компилятор что-то оптимизирует, а когда нет. И без понимания, как эти штуки устроены, и без чтения release notes ты этого просто не узнаешь.

Раньше было так: переписал LINQ-запрос и почти всегда получал ускорение. Но в .NET 10 это уже не так, потому что теперь он оптимизирует и LINQ тоже.

Вообще на современном .NET 10 и актуальной версии C# стало как никогда просто писать код на C#, который по перформансу близок к C++, а иногда даже обгоняет его. Потому что теперь есть LibraryImport, и он может генерировать MSIL-интероп код без runtime marshalling...

По сути, единственный реально сильный аргумент против C# вместо системных языков сейчас это сборщик мусора.

Если GC в твоем кейсе неприемлем, тогда да, бери системный язык. Но если GC не критичен, и ты не пишешь драйвер или код под embedded, то скорее всего C# тебе ок.

GC это реально единственное, что мешает делать AAA 3D игры на C#.

Но даже это сейчас довольно управляемо благодаря stackalloc, Memory<T>, Span<T> и ref struct.

Пулы памяти тоже теперь есть: можно создавать объекты из пула и переиспользовать RAM, что отлично для GPU-сцен, где хочется минимум мусора и аллокаций.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
13
This media is not supported in your browser
VIEW IN TELEGRAM
Как можно использовать состояние при работе с MediatR?

Популярный nuget-пакет MediatR по умолчанию не делает хендлеры stateful. То есть при обработке сообщения каждый раз создается новый инстанс хендлера.

Само по себе это не проблема, и я уверен, что это осознанное архитектурное решение... Но бывают ситуации, когда хочется иметь хотя бы какое-то состояние.

Например, что если тебе нужен кэш?

Самое простое решение: вынести ответственность за состояние в отдельный компонент. А дальше пусть dependency injection подсовывает этот компонент в хендлер.

Проблема решена ✌️

Полное видео тут

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🥴1
Git Tip: юзай команду git checkout -, чтобы быстро переключаться на предыдущую ветку, с которой ты только что работал.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🥴7😁2🔥1😐1
Начиная с Entity Framework 10 у нас появилась поддержка именованных (и нескольких) query filters 🥳

// Entity Framework 10 will support Named query filters:
modelBuilder.Entity<Blog>()
.HasQueryFilter("SoftDeletionFlter", b => !b.IsDeleted)
.HasQueryFilter("TenantFilter", b => b.TenantId == tenantId);

// this allows us to remove explicit query filters:
var allBlogs = await
context.Blogs.IgnoreQueryFilters(["SoftDeletionFlter"]).ToListAsync();


👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
1
API Gateway как RESTful-микросервис (версия 6.0)

Эта новая версия поддерживает .NET 10.
То есть теперь поддерживаются .NET 8/9/10.

hubs.li/Q041B9js0

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🤔2
This media is not supported in your browser
VIEW IN TELEGRAM
.NET 11 Preview 1 теперь доступен

Он приносит крупные улучшения в .NET Runtime, SDK, библиотеках, C#, ASP.NET Core, Blazor, .NET MAUI, новые анализаторы кода и не только. Полные release notes по ссылке. Можешь начинать пробовать уже сегодня.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍4🔥3
Если ты все еще сидишь на Swashbuckle в .NET 10, то вот что ты пропустил.

Swashbuckle нормально не обновлялся уже больше года. Поэтому Microsoft убрали его из шаблонов .NET 9+ и сделали свой встроенный вариант.

Замена: Microsoft.AspNetCore.OpenApi
Встроенный, легче, поддерживается и развивается.

UI: Scalar лучше, чем Swagger UI. Быстрее, выглядит приятнее, и темная тема есть из коробки.

Миграция реально на 5 минут: убираешь Swashbuckle, добавляешь builder.Services.AddOpenApi(), и готово.

Статья, которая поможет переехать: https://codewithmukesh.com/blog/dotnet-swagger-alternatives-openapi/

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20🔥4👎2
Асинхронное общение делает интеграционные тесты болью.

Ты шлёшь событие из одного модуля и... ждёшь?

Если опираться на Thread.sleep, твой CI/CD быстро начнёт страдать.

Не жди. Опрашивай.

Я использую паттерн “retry assertion” для проверки логики между модулями в модульных монолитах:

▪️Выполняем команду (модуль A)
▪️Поллим запрос (модуль B), пока Result != null
▪️Делаем ассерты по результату

Так флейковый, медленный тест превращается в детерминированный и быстрый.

Почитай про эту стратегию в статье

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍65
Статические абстрактные члены интерфейсов появились в C# 11. Основной мотивацией для них является поддержка обобщённой математики. Но они могут быть полезны и в других сценариях. Например, упростить код регистрации и использования типов разделов пользовательской конфигурации.

Например, вы хотите настроить клиент API в appSettings.json:

{

"GoogleAPI": {
"ApiKey": "…",
"OrganizationId": "…",

}
}


Хорошей практикой является связать раздел с отдельным типом:

public class GoogleOptions {
public string? ApiKey { get; init; }
public string? OrganizationId { get; init; }

}

// добавляем в Program.cs
builder.Configuration
.Configure<GoogleOptions>(
builder.Configuration.GetSection("GoogleAPI"));

// внедряем через DI
public class GoogleClient(
IOptions<GoogleOptions> options) {
// …
}


Упростим регистрацию через статические члены интерфейсов. Сначала определим интерфейс:

public interface IConfigOptions
{
static abstract string SectionName { get; }
}


Все реализации этого интерфейса должны иметь статическое свойство SectionName:

public class GoogleOptions: IConfigOptions {
public static string SectionName => "GoogleAPI";
// остальные члены
}


Добавим методы расширения для регистрации секций конфигурации:

public static class OptionsExtensions {
public static IHostApplicationBuilder
Configure<TOptions>(
this IHostApplicationBuilder builder)
where TOptions : class, IConfigOptions
{
var sect = builder.Configuration
.GetSection(TOptions.SectionName);
builder.Services.Configure<TOptions>(sect);
return builder;
}
}


Теперь можно регистрировать различные секции конфигурации так:

builder.Configure<GoogleOptions>()
.Configure<GitHubOptions>()
.Configure<WeatherOptions>()


👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
11🥴5
Все еще держишь бизнес-логику в сервисах Application-слоя?

Это обычно знак, что доменная модель почти ничего не делает.

Если твои entity выглядят как голые DTO с полями, то у тебя анемичная доменная модель.

Как рефакторнуться в сторону behavior-driven дизайна:

Проталкивай бизнес-логику в домен
Делай методы, которые жестко держат инварианты
Делай так, чтобы невалидные состояния были невозможны в принципе
Пересмотри границы сервисов

В итоге код проще сопровождать, тестировать и расширять.

Пошаговый разбор рефакторинга

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
2
This media is not supported in your browser
VIEW IN TELEGRAM
Чувак собрал терминальный осциллограф для OPC UA на чистом C#, с рендерингом через брайлевские символы для 8x “пиксельного” разрешения.

Пара C# моментов, из-за которых это было прям кайфово:

1. Брайлевские символы как пиксельный движок

Вид осциллографа рисует осциллограммы через Unicode braille (U+2800–U+28FF). Каждая ячейка терминала становится матрицей точек 2×4, то есть дает в 8 раз больше разрешения по сравнению с обычным “символ-в-ячейке” рендерингом. Кастомный класс BrailleCanvas делает маппинг координат, алгоритм линий Брезенхэма для связных трасс, и композитинг слоев, чтобы сигнал всегда был поверх точек сетки. Около 270 строк, без графических зависимостей.

2. Terminal.Gui v2 для UI

TreeView, TableView, диалоги, меню, поддержка мыши. Осциллограф это кастомный View, который переопределяет OnDrawingContent и общается с ConsoleDriver для брайлевого рендера.

3. Подписки OPC UA вместо polling

Значения пушатся через события MonitoredItem.Notification, а в UI прокидываются через Application.Invoke(). Данные прилетают настолько быстро, насколько их публикует сервер.

4. Кроссплатформа

Windows/Linux/macOS без условной компиляции.

Исходники

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17
Поддержка LeftJoin в Entity Framework 10+ 🥳
Круто, что наконец-то это добавили в 10-й версии.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🤣3
Типы связей в EF Core, по-простому:

1:N -> HasOne().WithMany()
1:1 -> HasOne().WithOne().HasForeignKey<T>()
M:N -> HasMany().WithMany()
M:N с данными в связи -> отдельная join-entity (явная сущность для таблицы-связки)

И да: всегда задавай OnDelete явно. Дефолтный Cascade угробил больше баз, чем кривые запросы.

Полный гайд с примерами кода

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥84
Ты можешь комбинировать raw SQL-запросы и LINQ в EF Core.

Вот пример: сначала выполняем SELECT через SQL, а потом докидываем цепочкой OrderBy + Skip + Take уже через LINQ.

Вот код с картинки (как есть):

var startDate = new DateOnly(2023, 1, 1);

var ordersIn2023 = await dbContext
.Database
.SqlQuery<OrderSummary>(
$"SELECT * FROM OrderSummaries AS o WHERE o.CreatedOn >= {startDate}")
.OrderBy(o => o.Id)
.Skip(10)
.Take(5)
.ToListAsync();


-- SQL sent to the DB
SELECT s.Id, s.CustomerId, s.TotalPrice, s.CreatedOn
FROM (
SELECT * FROM OrderSummaries AS o WHERE o.CreatedOn >= @p0
) AS s
ORDER BY s.Id
OFFSET @p1 ROWS FETCH NEXT @p2 ROWS ONLY


Обрати внимание: raw SQL-запрос здесь корректно параметризован, хотя на вид кажется, что мы используем интерполяцию строк.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥133👍3
Уикенд-проект: portless

Стабильные, “именованные” URL для локальной разработки.

▪️Ноль конфига
▪️Сабдомены для монореп
▪️Больше никакой рулетки с портами и протекания кук между сервисами
▪️Агентам можно давать надежный URL, вместо того чтобы угадывать порты

npm i -g portless


👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
Улучшения по производительности таймзон в dotnet 11

В .NET 11 добавили кэш переходов таймзон по годам (per-year cache) для TimeZoneInfo, из-за чего конвертация времени стала заметно быстрее. Кэш хранит все переходы за конкретный год в UTC и убирает повторные lookup-и правил при каждом пересчете.

По бенчмаркам ускорение такое:

▪️Windows: примерно в 2.4–3.9 раза быстрее (например, ConvertTimeFromUtc с 48.0 нс до 12.2 нс)
▪️Linux: примерно в 1.6–4.7 раза быстрее (например, ConvertTimeToUtc с 63.8 нс до 13.6 нс)

Плюс новый путь с кэшем заменил старую “слоеную” логику конвертации (которую годами патчили) и заодно поправил несколько багов, где конвертация могла давать неправильный результат.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥32👍1
Твой GET-эндпоинт возвращает все строки из таблицы. На 100 записей ок. На 100К это уже катастрофа.

3 вещи, которые нужны любому list-эндпоинту в .NET:

- Пагинация (Skip + Take)
- Динамическая сортировка (по нескольким колонкам)
- Поиск (без учета регистра)

И все это одним SQL-запросом через EF Core 10.

https://codewithmukesh.com/blog/pagination-sorting-searching-aspnet-core-webapi/

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯6👍3