C# Portal | Программирование – Telegram
C# Portal | Программирование
14.9K subscribers
966 photos
118 videos
24 files
809 links
Присоединяйтесь к нашему каналу и погрузитесь в мир для C#-разработчика

Связь: @devmangx

РКН: https://clck.ru/3FocB6
Download Telegram
Новая библиотека для планирования задач, которая превосходит Quartz и Hangfire

3 недели назад вышла новая библиотека под названием TickerQ.

Что такое TickerQ?

TickerQ — высокопроизводительный планировщик, разработанный специально для .NET. Он фокусируется на простоте, масштабируемости и минимальном потреблении ресурсов.

Почему она лучше?


Традиционные библиотеки, такие как Quartz и Hangfire, имеют известные недостатки:

↳ Quartz:
• Сложный API, тяжело для новичков
• Отсутствие типобезопасности при передаче параметров в Job
• Потери в производительности из-за использования рефлексии

↳ Hangfire:
• Ограниченная поддержка DI и async-операций
• Простейшая логика повторных попыток (retry)
• Потери в производительности из-за использования рефлексии

Как TickerQ решает эти проблемы:

1️⃣Легковесный и интуитивно понятный API
2️⃣Без рефлексии, использует source generators
3️⃣Нативная поддержка распределённого планирования без дополнительной сложности
4️⃣Встроенная логика повторных попыток и упрощённая обработка ошибок

Quartz и Hangfire долгое время были стандартом, но теперь есть лучший вариант.

Что думаете про эту новую библиотеку для планирования? Попробуете TickerQ или останетесь на Quartz или Hangfire?

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍196
До сих пор часто вижу такой паттерн:

if (items.Count() > 0)
{
// ...
}


Это неэффективно.

Почему?

🔸Count() проходит по всей коллекции или делает COUNT(*) в базе данных.
🔸Если тебе просто нужно проверить, есть ли элементы — используй Any().

Any() останавливается на первом найденном элементе.
В SQL это переводится в EXISTS, что значительно легче, чем COUNT(*).

Основные выводы:

🔸Используй Any() для проверки на наличие элементов.
🔸Используй Count() только если реально нужен точный размер коллекции.

Такие небольшие оптимизации имеют значение особенно когда приложение растёт и работает с большими объёмами данных.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍273
Горячее мнение:
ВАМ НЕ НУЖНЫ библиотеки для маппинга.


🔸Напиши конструктор
🔸Вызови конструктор
🔸Готово

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

В своих проектах я редко использую больше одного уровня маппинга.

И ещё реже какие-либо библиотеки для маппинга.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🤔32
.NET Aspire теперь поддерживает создание баз данных MySQL

И настройка занимает всего одну строку

С момента релиза в статусе General Availability, .NET Aspire изменил подход к созданию облачных приложений на .NET.

Менее чем в 30 строках кода вы можете настроить:

- API
- Базы данных
- Кэш

Плюс, сразу из коробки получаете дашборд, сервис-дискавери и телеметрию.

Что лично для меня круто — возможность добавить и создать целую базу данных одним методом.

Метод AddDatabase выполняет SQL-команду CREATE DATABASE с заданным именем на работающем контейнере или сервере.

Ранее эта функция поддерживала:

- SQL Server
- PostgreSQL

Но теперь, начиная с версии 9.3, добавлена поддержка MySQL.

Вам не нужно ничего дополнительно делать — ваш существующий вызов AddDatabase теперь автоматически создаёт базу данных.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
10😁2👍1
Пример Task.WhenEach в .NET 9

В .NET 9 появилась новая API — Task.WhenEach, которая позволяет обрабатывать асинхронные задачи по мере их завершения.

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

Ты уже пробовал эту новую фичу? 🔥

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥32👍85
Перестань совершать ЭТУ критическую ошибку при запуске нового software проекта:

Пытаться выстроить идеальную архитектуру с первого дня.

Мой главный инсайт про архитектуру ПО?

«Хорошая архитектура не статична. Она развивается.»


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

В этом и суть эволюционной архитектуры:

Вместо того чтобы сразу делать ставку на «правильную» абстракцию, собери минимально работающее решение и перестраивай его осознанно по мере изменения требований.


Эта концепция особенно хорошо укладывается, когда видишь её в действии. Вот 4 отличных репозитория на GitHub с реальными приложениями:

🔸Evolutionary Architecture

→ Один проект на GitHub, в котором показано, как начать с простой .NET-архитектуры, а затем эволюционно перейти к модульному монолиту и микросервисам по мере роста требований и кодовой базы.
→ Ссылка: https://github.com/evolutionary-architecture/evolutionary-architecture-by-example

🔸Booking to Cloud Architecture

→ Приложение для бронирования, реализованное тремя способами: монолит, модульный монолит и микросервисы.
→ Монолит: https://github.com/meysamhadeli/booking-monolith
→ Модульный монолит: https://github.com/meysamhadeli/booking-modular-monolith
→ Микросервисы: https://github.com/meysamhadeli/booking-microservices

Когда ты перестаёшь воспринимать архитектуру как то, что нужно «угадать» с первого дня, ты даёшь себе право на ошибку.

Право учиться.
Право адаптироваться.
И расти вместе с системой.

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


👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥123👍1
10 скрытых фич EF Core, которые используют сеньоры

1️⃣Shadow Properties
EF Core позволяет добавлять свойства, которых нет в классе, но которые присутствуют в базе данных.
Идеально подходят, например, для хранения данных аудита, не засоряя сущности лишними полями.

2️⃣Query Tags
Можно легко добавлять комментарии к SQL-запросам, которые генерирует EF Core.
Удобно при профилировании - в логах SQL сразу видно, откуда пришёл тот или иной медленный запрос.

3️⃣Compiled Queries
Часто используемые запросы можно скомпилировать заранее, чтобы не тратить ресурсы на парсинг каждый раз.
Повышает производительность при большом числе однотипных запросов.

4️⃣DbContext Pooling
Вместо того чтобы каждый раз создавать новый DbContext, можно переиспользовать уже созданные.
Существенно снижает потребление памяти и повышает производительность.

5️⃣Value Converters
Позволяют автоматически преобразовывать значения между .NET и базой данных.
Полезно для хранения кастомных типов, enum'ов и Value Object'ов.

6️⃣Temporal Tables
Позволяют отслеживать историю изменений данных прямо в базе.
Удобно для аудита, отката изменений и анализа исторических данных.

7️⃣Database Seeding
EF Core 9 добавил новые методы UseSeeding, UseAsyncSeeding для удобного наполнения базы начальными данными.

8️⃣Split Queries for Includes
Позволяет разбивать сложные запросы с Include на несколько простых.
Избегает проблем с громоздкими JOIN’ами и повышает производительность.

9️⃣Raw SQL Queries
Можно выполнять чистый SQL прямо из EF Core.
Полезно, когда нужно выжать максимум производительности или использовать специфичный функционал конкретной СУБД.

1️⃣0️⃣Миграции для нескольких баз данных
Можно легко управлять миграциями и схемами сразу для разных провайдеров.
Подходит для приложений, которые должны работать с несколькими СУБД (например, SQL Server, PostgreSQL, MySQL).

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥71
Proxy Design Pattern

Что такое паттерн Proxy?

Proxy предоставляет объект-заместитель, который контролирует доступ к другому объекту.
Это как пользоваться банковской картой вместо наличных — те же возможности, но с большим контролем.

Это один из паттернов структурной группы, которая фокусируется на том, как классы и объекты объединяются в более крупные и гибкие архитектуры.

🔸Когда стоит использовать

Используйте Proxy, когда нужно:

- реализовать ленивую инициализацию тяжёлых объектов;
- контролировать доступ к объекту (например, авторизация);
- логировать входящие запросы;
- кэшировать результаты;
- управлять удалёнными ресурсами (например, через сеть).

Proxy идеально подходит, когда нужно добавить поведение к объекту, не изменяя его исходный код — например, добавить проверки безопасности или метрики производительности.

🔸Как реализовать

1. Создайте класс Proxy, реализующий тот же интерфейс, что и основной сервис.
2. Proxy хранит ссылку на реальный объект и перехватывает все обращения к нему.
3. В зависимости от логики, прокси может:
- разрешить/запретить доступ;
- отложить создание объекта;
- закэшировать результат;
- добавить побочные эффекты (лог, метрики и т.д.).


🔸Распространённые типы Proxy:

- Virtual Proxy — отложенное создание объекта;
- Protection Proxy — контроль прав доступа;
- Remote Proxy — работа с удалёнными объектами;
- Caching Proxy — кэширование результатов вызова.

> Proxy может выполнять свои действия до или после делегирования запроса реальному объекту.

🔸Почему это работает

- клиент работает с Proxy, не зная о реальной реализации сервиса.
- Proxy продолжает работать даже если объект-сервис ещё не создан или временно недоступен.
- можно добавлять новые прокси, не меняя код клиента или сервиса.

🔸Недостатки

- Возможны задержки в ответах из-за дополнительной логики.
- Увеличивается сложность кода — появляются дополнительные классы и уровни абстракции.
- Непродуманная реализация Proxy может стать узким местом и источником багов (например, в многопоточности).

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
10🔥3👍1
Секретная фишка в C#, о которой никто не знает

Она позволяет создавать высокопроизводительные .NET-приложения.

Разработка надёжных, масштабируемых и быстрых .NET-приложений во многом зависит от того, как вы организуете конкуренцию и обработку данных.

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

Ранее для этого использовали такие конструкции, как Queue<T>, ConcurrentQueue<T> или BlockingCollection<T>.

Эти очереди оборачивали в классы и применяли для управления потоками данных.

Однако у таких решений есть существенный минус — сильная связанность кода. 💊

Channels в C# это малоизвестная, но мощная фишка, которая предлагает современный способ построения безопасных, асинхронных и высоконагруженных .NET-приложений.

Они реализуют паттерн "производитель-потребитель": один класс создаёт данные, другой их потребляет - при этом оба ничего не знают друг о друге.

Ключевым архитектурным моментом при работе с каналами является выбор между ограниченными и неограниченными каналами.

Вот гайд, где узнаете:

➡️ Что такое C# Channels?
➡️ Ограниченные vs. неограниченные каналы
➡️ Фоновая обработка через Channels
➡️ Применение каналов в боевом ASP.NET Core-приложении
➡️ Лучшие практики и советы по работе с Channels

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥75😁1
В модульной монолитной архитектуре каждый модуль должен полноценно владеть своими данными. Для каждого модуля в PostgreSQL следует использовать отдельную схему и роль, а в EF Core — отдельный DbContext и строку подключения. Чтение данных между модулями должно выполняться через read model или представление , а не с помощью неконтролируемых join-ов

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥5🥴1😐1
Числовой StringComparer появится в dotnet 10

Он позволяет сравнивать числа по их числовому значению, а не в лексикографическом порядке.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
18🔥11
LINQ-метод Shuffle() появится в .NET 10

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

LINQ уже включает API для изменения порядка элементов, такие как OrderBy() и Reverse().
Однако на данный момент нет стандартного API для перемешивания IEnumerable<T>.

(Существует System.Random.Shuffle() для Span<T>, но если нужно перемешать произвольную последовательность IEnumerable<T>, скорее всего, придётся писать собственную реализацию.)

На StackOverflow часто можно встретить примеры перемешивания с использованием кода вроде .OrderBy(_ => Guid.NewGuid()).
Однако такой подход неэффективен, и есть более оптимальные способы перемешивания.

Поэтому предлагается реализовать System.Linq.Shuffle().

🔸API Proposal — Предложение API

namespace System.Linq
{
public static class Enumerable
{
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source) { }
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random randomSource) { }
}
}


🔸API Usage — Пример использования

var songs = ["Lorem", "ipsum", "dolor", "sit", "amet"];
foreach (var song in songs.Shuffle())
{
Play(song);
}

// выбрать 3 уникальные песни
var threeSongs = songs.Shuffle().Take(3).ToArray();


👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
13
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥27😁193
Рендеринг шаблона в PDF с помощью PuppeteerSharp:

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍3🤔1
Первичные конструкторы в dotnet

ДО .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 (Использование Primary Constructor):

public class UserService(
HospitalDBContext _dbContext,
ILogger<UserService> _logger,
IEmailService _emailService)
{
// Методы бизнес-логики здесь...
}


Круто или нет?

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥20🤨96🐳3😁1
Не совершайте эту ошибку

Не используйте .ToLower() для сравнения строк. Почему?

Метод .ToLower() создаёт новую строку в памяти для каждого сравнения, что приводит к лишним аллокациям.

Представьте метод, который вызывается очень часто — это может деградировать производительность приложения.

Кроме того, .ToLower() чувствителен к культуре, то есть результат может различаться в зависимости от текущей культуры, установленной в исполняющем потоке.

Что использовать вместо этого?

В .NET есть мощное перечисление — StringComparison.

Возможные варианты StringComparison:

- Ordinal — используйте в большинстве случаев, когда культурные правила не важны. Самый быстрый вариант.
- OrdinalIgnoreCase — для сравнений без учёта регистра, где культурные правила не имеют значения.
- CurrentCulture и CurrentCultureIgnoreCase — используйте при сравнении строк, отображаемых пользователю, так как они учитывают культурные правила.
- InvariantCulture и InvariantCultureIgnoreCase — подходят, когда нужна единообразная логика вне зависимости от культуры, например, при сохранении и извлечении данных.

> EF Core выбросит исключение, если использовать методы вроде
> String.Equals(string, StringComparison), так как они не транслируются в SQL.

Это не будет работать с EF.
Если вы используете SQL Server с коллацией по умолчанию, сравнение строк уже нечувствительно к регистру, поэтому обычное a == b или string.Equals(a, b) в LINQ будет работать.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍333
Посмотрите этот классный open-source инструмент для визуализации JSON-данных в интерактивных графах.

Он предлагает функции конвертации JSON в другие форматы (CSV, YAML), генерацию JSON Schema, выполнение запросов и экспорт визуализаций в виде изображений.

Также он умеет форматировать, валидировать и создавать интерфейсы TypeScript.

Репозиторий: https://github.com/AykutSarac/jsoncrack.com

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍148🥴2
Что нового в C# 14

Главные апдейты

Extension members теперь можно расширять не только методами но и свойствами и индексаторами плюс есть статические расширения для самого типа.

field как контекстный токен для простых автосвойств с логикой сеттера без явного бэкинг филда.

Условный доступ слева от присваивания то есть ?. и ?[] можно ставить перед тем что присваиваешь удобно и безопасно.

nameof понимает «пустой» дженерик тип например nameof(List<>).

Модификаторы у параметров простых лямбд ref, in, out, scoped теперь можно без явного типа.

Больше не мучаемся со Span<T> и ReadOnlySpan<T> стало больше неявных конверсий и это лучше дружит с инференсом и экстеншенами.

Больше partial теперь можно частично объявлять конструкторы и события.

Пользовательские составные операторы присваивания то есть можно задавать свою семантику для вроде +=.

Пара мини примеров

field в действии

public class Box
{
public string Title
{
get;
set => field = value ?? throw new ArgumentNullException(nameof(value));
}
}


Условное присваивание

customer?.Order = FetchOrder();
bag?["count"] += 1;


nameof с незаполненным дженериком

var n = nameof(List<>); // "List"


Модификатор у лямбды без явных типов

delegate void Bump(ref int x);
Bump inc = (ref x) => x++;


Как попробовать


Ставишь свежий .NET 10 SDK и актуальный Visual Studio 2022 эти фичи уже в превью ветки для десятки. Страница с новыми фичами обновлялась под .NET 10 Preview 1 в апреле 2025.

🔸подробнее - https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
15😁1