API Gateway и Load Balancer часто путают новички, но это база для любого бэкенд разработчика
API Gateway работает как входная точка
• это единая точка, куда стучатся клиенты, он берет на себя всю первичную обработку запросов
• умный слой, который управляет авторизацией и аутентификацией (AuthN), rate limiting, логированием, мониторингом запросов и маршрутизацией
• идеально подходит для микросервисов, потому что централизует управление API во всей системе
• работает на уровне приложения L7
Load Balancer работает как распределитель трафика
• его задача распределять входящие запросы между группой одинаковых серверов
• нужен чтобы повысить пропускную способность, уменьшить задержки и не допускать перегрузки одного сервера
• подходит для систем с высокой нагрузкой, где важна отказоустойчивость и стабильное распределение трафика
• может работать как на уровне приложения L7, так и на транспортном уровне L4
API Gateway управляет, валидирует и контролирует API запросы (про сложность)
Load Balancer равномерно распределяет трафик и оптимизирует нагрузку (про производительность)
👉 @KodBlog
API Gateway работает как входная точка
• это единая точка, куда стучатся клиенты, он берет на себя всю первичную обработку запросов
• умный слой, который управляет авторизацией и аутентификацией (AuthN), rate limiting, логированием, мониторингом запросов и маршрутизацией
• идеально подходит для микросервисов, потому что централизует управление API во всей системе
• работает на уровне приложения L7
Load Balancer работает как распределитель трафика
• его задача распределять входящие запросы между группой одинаковых серверов
• нужен чтобы повысить пропускную способность, уменьшить задержки и не допускать перегрузки одного сервера
• подходит для систем с высокой нагрузкой, где важна отказоустойчивость и стабильное распределение трафика
• может работать как на уровне приложения L7, так и на транспортном уровне L4
API Gateway управляет, валидирует и контролирует API запросы (про сложность)
Load Balancer равномерно распределяет трафик и оптимизирует нагрузку (про производительность)
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤2😁1
C# 14: Extension Members и как они помогают polyfill-библиотекам
C# давно поддерживает extension-методы, которые позволяют добавлять новые методы к существующим типам, не трогая исходный код. Но раньше это касалось только инстанс-методов. В C# 14 появились extension members, и область расширения заметно выросла. Теперь можно добавлять extension-свойства и extension-статические методы к существующим типам. Такая фича особенно полезна для polyfill-библиотек, которые позволяют использовать новые API в старых версиях .NET.
Polyfill-библиотеки помогают писать код с использованием современных API, но при этом таргетировать разные версии .NET. В предыдущем посте про polyfills я объяснял, что смысл таких библиотек заключается в том, чтобы предоставить реализацию новых API для старых фреймворков и уменьшить количество
До выхода C# 14 polyfill-библиотеки могли добавлять только инстанс-методы через extension methods. Это означало, что статические методы и свойства из новых версий .NET нормально не покрывались polyfill'ами. C# 14 снимает это ограничение и позволяет polyfill-библиотекам выглядеть куда полнее и нативнее.
Хороший пример это статический метод ArgumentNullException.ThrowIfNull, который появился в .NET 6. Он дает удобный способ проверить аргументы на null:
До C# 14 polyfill-библиотеки не могли добавить ThrowIfNull как статический метод ArgumentNullException, потому что extension методы работали только с инстансами. В C# 14 можно определить extension static method, и polyfill-библиотеки могут предоставить идентичный API даже для старых версий .NET. Теперь можно использовать ArgumentNullException.ThrowIfNull независимо от target framework, и код будет выглядеть единообразно и чище.
Конечно, можно писать свои extension static-методы и свойства, но проще воспользоваться уже поддерживаемой polyfill-библиотекой.
Пакет Meziantou.Polyfill (GitHub) может покрывать более 350 типов, методов и свойств. Он использует возможности C# 14, чтобы дать максимально полное polyfill-решение. Пакет основан на source generators, которые автоматически добавляют только те polyfills, которые реально нужны под ваш target framework.
Установка:
После установки можно использовать новые API вроде ArgumentNullException.ThrowIfNull даже при таргете на старые платформы, вроде .NET Standard 2.0 или .NET Framework:
Source generator автоматически определяет target framework, версию C# и опции компиляции, и генерирует extension members только тогда, когда это возможно и реально требуется. Если вы не используете C# 14 или ваш target framework уже содержит нужный API, polyfill просто не будет создан.
👉 @KodBlog
C# давно поддерживает extension-методы, которые позволяют добавлять новые методы к существующим типам, не трогая исходный код. Но раньше это касалось только инстанс-методов. В C# 14 появились extension members, и область расширения заметно выросла. Теперь можно добавлять extension-свойства и extension-статические методы к существующим типам. Такая фича особенно полезна для polyfill-библиотек, которые позволяют использовать новые API в старых версиях .NET.
Polyfill-библиотеки помогают писать код с использованием современных API, но при этом таргетировать разные версии .NET. В предыдущем посте про polyfills я объяснял, что смысл таких библиотек заключается в том, чтобы предоставить реализацию новых API для старых фреймворков и уменьшить количество
#if в проекте.До выхода C# 14 polyfill-библиотеки могли добавлять только инстанс-методы через extension methods. Это означало, что статические методы и свойства из новых версий .NET нормально не покрывались polyfill'ами. C# 14 снимает это ограничение и позволяет polyfill-библиотекам выглядеть куда полнее и нативнее.
Хороший пример это статический метод ArgumentNullException.ThrowIfNull, который появился в .NET 6. Он дает удобный способ проверить аргументы на null:
public void ProcessData(string data)
{
ArgumentNullException.ThrowIfNull(data);
// Process the data...
}
До C# 14 polyfill-библиотеки не могли добавить ThrowIfNull как статический метод ArgumentNullException, потому что extension методы работали только с инстансами. В C# 14 можно определить extension static method, и polyfill-библиотеки могут предоставить идентичный API даже для старых версий .NET. Теперь можно использовать ArgumentNullException.ThrowIfNull независимо от target framework, и код будет выглядеть единообразно и чище.
static class PolyfillExtensions
{
extension(ArgumentNullException)
{
public static void ThrowIfNull([NotNull] object? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null)
{
if (argument is null)
throw new ArgumentNullException(paramName);
}
}
}
Конечно, можно писать свои extension static-методы и свойства, но проще воспользоваться уже поддерживаемой polyfill-библиотекой.
Пакет Meziantou.Polyfill (GitHub) может покрывать более 350 типов, методов и свойств. Он использует возможности C# 14, чтобы дать максимально полное polyfill-решение. Пакет основан на source generators, которые автоматически добавляют только те polyfills, которые реально нужны под ваш target framework.
Установка:
dotnet add package Meziantou.PolyfillПосле установки можно использовать новые API вроде ArgumentNullException.ThrowIfNull даже при таргете на старые платформы, вроде .NET Standard 2.0 или .NET Framework:
public class UserService
{
public void CreateUser(string username, string email)
{
// Работает в .NET Standard 2.0 благодаря extension static methods
ArgumentNullException.ThrowIfNull(username);
ArgumentNullException.ThrowIfNull(email);
// Create user logic...
}
}
Source generator автоматически определяет target framework, версию C# и опции компиляции, и генерирует extension members только тогда, когда это возможно и реально требуется. Если вы не используете C# 14 или ваш target framework уже содержит нужный API, polyfill просто не будет создан.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤3🔥3
На Хабре разобрали YARP — это быстрый reverse proxy на .NET, и его можно удобно конфигурировать прямо в
Под капотом есть всё, что нужно для продовой нагрузки:
• поддержка HTTP/2 и gRPC
• трансформации путей и заголовков
• балансировка трафика (RoundRobin, PowerOfTwoChoices и другие алгоритмы)
• health-checks и session affinity
• TLS-терминация
В статье есть разбор, примеры конфигурации и демо от OTUS
👉 @KodBlog
ASP.NET Core через appsettings.json.Под капотом есть всё, что нужно для продовой нагрузки:
• поддержка HTTP/2 и gRPC
• трансформации путей и заголовков
• балансировка трафика (RoundRobin, PowerOfTwoChoices и другие алгоритмы)
• health-checks и session affinity
• TLS-терминация
В статье есть разбор, примеры конфигурации и демо от OTUS
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤4🔥2
C# expression-bodied члены просто топ.
А теперь к делу. Вот способ использовать enum для сортировки строк, которые сами по себе ничего не значат.
Бывало, что нужно отсортировать данные, пришедшие откуда-то извне, например из веб-API, где нет нормального поля для сортировки? Enum может стать небольшим хаком и избавить от магических строк.
👉 @KodBlog
А теперь к делу. Вот способ использовать enum для сортировки строк, которые сами по себе ничего не значат.
Бывало, что нужно отсортировать данные, пришедшие откуда-то извне, например из веб-API, где нет нормального поля для сортировки? Enum может стать небольшим хаком и избавить от магических строк.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8
В Visual Studio 2026 появилась возможность отключать отображение символов под файлами C# и C++ в Solution Explorer, и эта функция скоро станет доступна.
👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15😁6👎2❤1👏1
Оптимизация производительности создания GUID в .NET приложениях
Во многих .NET проектах GUID используют как идентификаторы для активностей, interop-сценариев, ключей в базах данных и многого другого. Часто можно встретить код вида new Guid("01234567-8901-2345-6789-012345678901"). Такой способ читаемый и простой, но у него есть скрытая цена = он может замедлять старт приложения.
Создание GUID из строки требует парсинга строкового представления, а это уже дополнительные операции. Плюс .NET поддерживает несколько форматов строковых GUID (с фигурными скобками, без, с дефисами и т.д.), из-за чего логика парсинга тоже усложняется.
Если GUID зашит в коде, эту нагрузку можно убрать, используя конструктор Guid, который принимает числовые параметры.
Например, строковое создание GUID:
Можно заменить на:
Так GUID собирается напрямую из числовых компонентов, без парсинга строки. Минус в том, что читаемость страдает, и вручную конвертировать строку в numeric-формат легко ошибиться. Плюс такой код сложнее искать в проекте. Решением будет оставлять строковое значение как комментарий.
Автоматическое обнаружение с Meziantou.Analyzer
Чтобы находить такие места автоматически, Meziantou.Analyzer содержит правило MA0176, которое ищет создание GUID из строковых литералов и предлагает использовать numeric-конструктор.
Устанавливается через .NET CLI или добавлением в csproj.
CLI:
Или в .csproj:
MA0176 ловит такие случаи и предлагает оптимизацию:
И автоматически заменяет на:
// Оптимизированный вариант
new Guid(0x01234567, 0x8901, 0x2345, 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89, 0x01) /* 01234567-8901-2345-6789-012345678901 */;
Бенчмарк
Использовался BenchmarkDotNet для сравнения:
Разница огромная (×1000 в пользу числового конструктора), но в большинстве приложений создаётся мало фиксированных GUID, поэтому влияние на общую производительность минимальное. Но при старте приложения, а особенно в сценариях вроде Azure Functions или AWS Lambda, где важны cold start задержки, эта оптимизация может помочь.
👉 @KodBlog
Во многих .NET проектах GUID используют как идентификаторы для активностей, interop-сценариев, ключей в базах данных и многого другого. Часто можно встретить код вида new Guid("01234567-8901-2345-6789-012345678901"). Такой способ читаемый и простой, но у него есть скрытая цена = он может замедлять старт приложения.
Важно отметить, что это микрооптимизация, которая в основном полезна в случаях, когда GUID создаются во время запуска приложения. Для обычного кода разница практически незаметна (смотри бенчмарк ниже).
Создание GUID из строки требует парсинга строкового представления, а это уже дополнительные операции. Плюс .NET поддерживает несколько форматов строковых GUID (с фигурными скобками, без, с дефисами и т.д.), из-за чего логика парсинга тоже усложняется.
Если GUID зашит в коде, эту нагрузку можно убрать, используя конструктор Guid, который принимает числовые параметры.
Например, строковое создание GUID:
var guid = new Guid("01234567-8901-2345-6789-012345678901");Можно заменить на:
var guid = new Guid(0x01234567, 0x8901, 0x2345, 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89, 0x01);
Так GUID собирается напрямую из числовых компонентов, без парсинга строки. Минус в том, что читаемость страдает, и вручную конвертировать строку в numeric-формат легко ошибиться. Плюс такой код сложнее искать в проекте. Решением будет оставлять строковое значение как комментарий.
Автоматическое обнаружение с Meziantou.Analyzer
Чтобы находить такие места автоматически, Meziantou.Analyzer содержит правило MA0176, которое ищет создание GUID из строковых литералов и предлагает использовать numeric-конструктор.
Устанавливается через .NET CLI или добавлением в csproj.
CLI:
dotnet add package Meziantou.AnalyzerИли в .csproj:
<PackageReference Include="Meziantou.Analyzer" Version="2.0.224">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
MA0176 ловит такие случаи и предлагает оптимизацию:
// Строковое создание (будет замечено анализатором)
_ = new Guid("01234567-8901-2345-6789-012345678901");
_ = Guid.Parse("01234567-8901-2345-6789-012345678901");
И автоматически заменяет на:
// Оптимизированный вариант
new Guid(0x01234567, 0x8901, 0x2345, 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89, 0x01) /* 01234567-8901-2345-6789-012345678901 */;
Бенчмарк
Использовался BenchmarkDotNet для сравнения:
public class NewGuid
{
[Benchmark(Baseline = true)]
public Guid GuidParse() => Guid.Parse("01234567-8901-2345-6789-012345678901");
[Benchmark]
public Guid NewGuidString() => new Guid("01234567-8901-2345-6789-012345678901");
[Benchmark]
public Guid NewGuidComponents() => new Guid(0x01234567, 0x8901, 0x2345, 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89, 0x01);
}
GuidParse:
Mean 23.4168 ns
Error 0.4823 ns
StdDev 0.4511 ns
Median 23.3622 ns
NewGuidString:
Mean 22.6531 ns
Error 0.3757 ns
StdDev 0.3514 ns
Median 22.7011 ns
NewGuidComponents:
Mean 0.0215 ns
Error 0.0170 ns
StdDev 0.0366 ns
Median 0.0000 ns
Разница огромная (×1000 в пользу числового конструктора), но в большинстве приложений создаётся мало фиксированных GUID, поэтому влияние на общую производительность минимальное. Но при старте приложения, а особенно в сценариях вроде Azure Functions или AWS Lambda, где важны cold start задержки, эта оптимизация может помочь.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🤔6👍3🥴2
Polly остаётся основным выбором для реализации отказоустойчивости в .NET, особенно теперь, когда он быстрее в V8+, и это важно, потому что HTTP-запросы могут падать из-за сетевых или серверных проблем, создавая риск каскадных отказов, а официальная библиотека resilience в .NET всего лишь обёртка над Polly с OpenTelemetry.
Вот как сделать приложение устойчивым: читать
👉 @KodBlog
Вот как сделать приложение устойчивым: читать
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍3
Перегрузка операторов в C# 14 выходит на новый уровень и теперь вопрос только в том, стоит ли принимать такие замороченные варианты в кодовой базе, потому что подобные штуки могут взорвать мозг многим разработчикам
👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯34👍12❤7👏1
Не злоупотребляй select * в запросах к базе.
Почему это плохо:
Схема может измениться, появятся новые поля, например огромная JSONB колонка, и ты внезапно начнешь таскать лишний трафик и грузить память.
Нельзя нормально использовать covering indexes, потому что запрос требует все колонки, а не только нужные.
Запрашивай только те поля, которые реально нужны в проде.
👉 @KodBlog
Почему это плохо:
Схема может измениться, появятся новые поля, например огромная JSONB колонка, и ты внезапно начнешь таскать лишний трафик и грузить память.
Нельзя нормально использовать covering indexes, потому что запрос требует все колонки, а не только нужные.
Запрашивай только те поля, которые реально нужны в проде.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🥴3
Разбираемся с основами работы с FakeLogger.
Мокать зависимости бывает неудобно, особенно если интерфейс не принадлежит вам, и взаимодействие с ним в коде идет через extension-методы. Так обстоит дело с ILogger из базовой инфраструктуры логирования Microsoft. Сам интерфейс ILogger довольно простой, но на практике вы почти никогда не работаете с ним напрямую. Тогда как протестировать, что вызывается правильный метод и параметры, чтобы убедиться что логирование работает корректно?
Раньше я писал о том, как замокать ILogger<> через Moq, передать его в SUT (system under test) и проверить вызовы. Это рабочий вариант, но он громоздкий, плюс код проверки приходится копировать между проектами. Не лучший вариант.
И тут появляется FakeLogger!
FakeLogger дает полный доступ ко всем данным, которые проходят через вызовы ILogger в вашем коде, и позволяет удобно писать ассерты в тестах.
Пакет немного переезжал, но сейчас он находится в Microsoft.Extensions.Diagnostics.Testing и доступен через пространство имен Microsoft.Extensions.Logging.Testing, как и ожидаешь.
После того как вы подключили NuGet-пакет в проект с тестами, можно начинать использовать его в юнит-тестах.
Простой пример
Для демонстрации возьмем небольшой SUT.
В этом сервисе нужно протестировать, что при вызове LogMe используется корректный метод логирования.
Начнем с создания экземпляра FakeLogger и SUT:
FakeLogger<> реализует нужный интерфейс, так что мы можем просто передать его в DemoService.
После выполнения Act-части теста (в AAA-подходе) можно проверять результат:
Самый простой способ — обратиться к свойству LatestRecord у fakeLogger. Оно содержит последний вызов логгера внутри SUT. На этом базовое использование заканчивается.
В этом посте мы разобрали, как использовать FakeLogger при тестировании, когда системе нужен ILogger. Инструмент позволяет проверять уровни логирования, тексты сообщений и структурированные данные, которые передаются в лог.
Вы все еще пишете свою обертку или уже переходите на FakeLogger?🐵
👉 @KodBlog
Мокать зависимости бывает неудобно, особенно если интерфейс не принадлежит вам, и взаимодействие с ним в коде идет через extension-методы. Так обстоит дело с ILogger из базовой инфраструктуры логирования Microsoft. Сам интерфейс ILogger довольно простой, но на практике вы почти никогда не работаете с ним напрямую. Тогда как протестировать, что вызывается правильный метод и параметры, чтобы убедиться что логирование работает корректно?
Раньше я писал о том, как замокать ILogger<> через Moq, передать его в SUT (system under test) и проверить вызовы. Это рабочий вариант, но он громоздкий, плюс код проверки приходится копировать между проектами. Не лучший вариант.
И тут появляется FakeLogger!
FakeLogger дает полный доступ ко всем данным, которые проходят через вызовы ILogger в вашем коде, и позволяет удобно писать ассерты в тестах.
Пакет немного переезжал, но сейчас он находится в Microsoft.Extensions.Diagnostics.Testing и доступен через пространство имен Microsoft.Extensions.Logging.Testing, как и ожидаешь.
После того как вы подключили NuGet-пакет в проект с тестами, можно начинать использовать его в юнит-тестах.
Простой пример
Для демонстрации возьмем небольшой SUT.
public class DemoService(ILogger<DemoService> logger)
{
public void LogMe()
{
logger.LogInformation("This should be logged.");
}
}
В этом сервисе нужно протестировать, что при вызове LogMe используется корректный метод логирования.
Начнем с создания экземпляра FakeLogger и SUT:
var fakeLogger = new FakeLogger<DemoService>();
var sut = new DemoService(fakeLogger);
FakeLogger<> реализует нужный интерфейс, так что мы можем просто передать его в DemoService.
После выполнения Act-части теста (в AAA-подходе) можно проверять результат:
fakeLogger.LatestRecord.Message.Should().Be("This should be logged.");Самый простой способ — обратиться к свойству LatestRecord у fakeLogger. Оно содержит последний вызов логгера внутри SUT. На этом базовое использование заканчивается.
В этом посте мы разобрали, как использовать FakeLogger при тестировании, когда системе нужен ILogger. Инструмент позволяет проверять уровни логирования, тексты сообщений и структурированные данные, которые передаются в лог.
Вы все еще пишете свою обертку или уже переходите на FakeLogger?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🔥3
Уже полгода в программировании, а в голове каша?
Знакомо? Дело не в вас.
Вас подвела система: куски информации без структуры и обратной связи.
Нашел годный курс Основы программирования:
✔️ Практика с первого дня, а не через месяц скучной теории
✔️ Поддержка от команды курса. Всегда отвечают на вопросы
✔️ Нет привязки ко времени. Можете учиться в своем темпе, когда угодно и сколько угодно
Прямо сейчас идет Чёрная Пятница — скидка 20%
98 630 человек уже начали учиться.
Посмотрите *1 031* реальных отзывов и начните наконец двигаться к цели.
👉 Даже можно попробовать проходить курс бесплатно:
https://stepik.org/lesson/1263653/step/1?unit=1277776
А если основы C# уже знаете, у нас есть продвинутые курсы:
https://stepik.org/org/PRO_csharp
Знакомо? Дело не в вас.
Вас подвела система: куски информации без структуры и обратной связи.
Нашел годный курс Основы программирования:
✔️ Практика с первого дня, а не через месяц скучной теории
✔️ Поддержка от команды курса. Всегда отвечают на вопросы
✔️ Нет привязки ко времени. Можете учиться в своем темпе, когда угодно и сколько угодно
Прямо сейчас идет Чёрная Пятница — скидка 20%
98 630 человек уже начали учиться.
Посмотрите *1 031* реальных отзывов и начните наконец двигаться к цели.
👉 Даже можно попробовать проходить курс бесплатно:
https://stepik.org/lesson/1263653/step/1?unit=1277776
А если основы C# уже знаете, у нас есть продвинутые курсы:
https://stepik.org/org/PRO_csharp
❤4🔥4👌3👍1
Ты можешь ловить уязвимости в коде ещё на этапе сборки.
Вот простой способ сделать это в .NET буквально за пару минут.
Представь, что можешь находить проблемы с безопасностью каждый раз, когда собираешь проект.
Статический анализ кода позволяет это сделать.
Вот пример ошибки при билде, где меня предупреждают, что мой код для хеширования пароля небезопасен.👇
Статический анализ помогает писать более безопасный и единообразный код. И его можно заставить работать на этапе сборки, включая CI пайплайны.
Если хочешь посмотреть, как настроить это с нуля, загляни в статью
Имей в виду, что такой подход не поймает абсолютно все проблемы.
Если хочешь пойти глубже, посмотри в сторону более мощных инструментов вроде SonarQube.
@KodBlog
Вот простой способ сделать это в .NET буквально за пару минут.
Представь, что можешь находить проблемы с безопасностью каждый раз, когда собираешь проект.
Статический анализ кода позволяет это сделать.
Вот пример ошибки при билде, где меня предупреждают, что мой код для хеширования пароля небезопасен.
Статический анализ помогает писать более безопасный и единообразный код. И его можно заставить работать на этапе сборки, включая CI пайплайны.
Если хочешь посмотреть, как настроить это с нуля, загляни в статью
Имей в виду, что такой подход не поймает абсолютно все проблемы.
Если хочешь пойти глубже, посмотри в сторону более мощных инструментов вроде SonarQube.
@KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🔥1🤔1
Разрабатывать приложения под Windows и добавлять туда AI-функции вроде распознавания изображений, генерации текста и прочего бывает долго и муторно, если настраивать модели и писать всё с нуля.
Поэтому Microsoft выложила в открытый доступ инструмент AI Dev Gallery. Он сделан специально для Windows-разработчиков и помогает быстро подключать модели и интегрировать разные AI-возможности.
Там есть больше 25 интерактивных примеров, которые покрывают работу с изображениями, текстом, голосом и другими задачами. Модели можно сразу просматривать и скачивать с Hugging Face и GitHub.
Каждый пример включает полный исходник на C#, и его можно экспортировать в самостоятельный проект Visual Studio одним кликом, чтобы дальше спокойно дорабатывать.
Установить можно через Microsoft Store или клонировать репозиторий и собрать проект в Visual Studio 2022 или новеe
👉 @KodBlog
Поэтому Microsoft выложила в открытый доступ инструмент AI Dev Gallery. Он сделан специально для Windows-разработчиков и помогает быстро подключать модели и интегрировать разные AI-возможности.
Там есть больше 25 интерактивных примеров, которые покрывают работу с изображениями, текстом, голосом и другими задачами. Модели можно сразу просматривать и скачивать с Hugging Face и GitHub.
Каждый пример включает полный исходник на C#, и его можно экспортировать в самостоятельный проект Visual Studio одним кликом, чтобы дальше спокойно дорабатывать.
Установить можно через Microsoft Store или клонировать репозиторий и собрать проект в Visual Studio 2022 или новеe
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11🤔1
This media is not supported in your browser
VIEW IN TELEGRAM
Внутри 20+ модулей: от установки Linux и работы с файлами до сетей, прав, дисков, процессов, автоматизации на Bash и многого другого. Всё сразу закрепляется на практике (200+ заданий с автопроверкой).
Материал подаётся понятным языком, шаг за шагом, на реальных примерах и с наглядными схемами.
После прохождения вы получите сертификат, который можно добавить в резюме.
Есть бесплатные демо-уроки для ознакомления. В ближайшие 48ч курс доступен со скидкой 30% по промокоду «
STBLACKFRIDAY30»: открыть курс на StepikPlease open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1🍌1
Не делайте вот так в EF-запросах
Как решить проблему N+1⬇️
Оптимизация производительности:
Запрос внутри цикла:
Если выполнять запрос внутри цикла, будет происходить множество обращений к базе. Это создаёт лишние roundtrip-и и сильно просаживает производительность, особенно при больших выборках или большом количестве итераций.
Запрос вне цикла:
Если заранее получить все нужные данные одним запросом и обработать их уже в памяти, то число обращений к базе сокращается и производительность становится заметно выше. Этот подход куда эффективнее, когда нужно работать с множественными итерациями.
👉 @KodBlog
Как решить проблему N+1
Оптимизация производительности:
Запрос внутри цикла:
Если выполнять запрос внутри цикла, будет происходить множество обращений к базе. Это создаёт лишние roundtrip-и и сильно просаживает производительность, особенно при больших выборках или большом количестве итераций.
Запрос вне цикла:
Если заранее получить все нужные данные одним запросом и обработать их уже в памяти, то число обращений к базе сокращается и производительность становится заметно выше. Этот подход куда эффективнее, когда нужно работать с множественными итерациями.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🥴4💯4
Когда работаешь с Entity Framework Core, важно понимать, как работает слежение за изменениями (change tracking). Это влияет и на производительность, и на корректность данных. Я знал про метод AsNoTracking(), но во время code review наткнулся на менее известную, но очень полезную альтернативу: AsNoTrackingWithIdentityResolution().
Разберёмся, чем этот метод отличается и когда его стоит применять.
Коротко: что делает AsNoTracking()?
Прежде чем перейти к AsNoTrackingWithIdentityResolution, напомним, что делает AsNoTracking(). По умолчанию EF Core отслеживает все полученные сущности в change tracker. Это позволяет:
- автоматически фиксировать изменения объектов
- выполнять обновления без явного Attach
- обеспечивать identity resolution (один объект в памяти на одну запись в базе)
Но отслеживание имеет накладные расходы. Если запрос read-only и обновлять данные не нужно, то AsNoTracking() повышает производительность, отключая tracking целиком.
// Без отслеживания — быстрее для read-only сценариев
Хотя AsNoTracking() ускоряет работу, он создаёт тонкий, но важный побочный эффект: дублирующиеся сущности. Так как change tracker не занимается identity resolution, в памяти могут появляться несколько экземпляров одной и той же сущности.
Пример:
Если несколько заказов принадлежат одному и тому же пользователю, EF создаст отдельные экземпляры Customer для каждого заказа. В итоге это приводит к:
- лишнему потреблению памяти
- проблемам при сравнении объектов
- потере целостности графа объектов
Появляется AsNoTrackingWithIdentityResolution()
AsNoTrackingWithIdentityResolution() решает эту проблему и даёт баланс между:
- отсутствием tracking (производительность)
- сохранением identity resolution (один объект на сущность)
Как работает AsNoTrackingWithIdentityResolution():
- EF не добавляет сущности в change tracker
- во время материализации создаётся временная identity map
- сущности с одинаковым ключом указывают на один объект
- identity map удаляется после выполнения запроса
То есть мы получаем identity resolution при выполнении запроса, но без постоянных затрат tracking.
Если этот режим нужен часто, можно выставить его по умолчанию:
Когда что использовать
✔️ Default Tracking если:
- нужно обновлять, удалять или отслеживать изменения
- небольшой набор данных
- требуется автоматическое обнаружение изменений
✔️ AsNoTracking если:
- запрос read-only
- нет навигационных свойств или связанных сущностей
- критична максимальная производительность
- результат не содержит повторяющихся сущностей
✔️ AsNoTrackingWithIdentityResolution если:
- read-only запрос с Include/Join
- важна целостность графа объектов
- результаты содержат повторяющиеся сущности
- нужно сравнение объектов по ссылке
👉 @KodBlog
Разберёмся, чем этот метод отличается и когда его стоит применять.
Коротко: что делает AsNoTracking()?
Прежде чем перейти к AsNoTrackingWithIdentityResolution, напомним, что делает AsNoTracking(). По умолчанию EF Core отслеживает все полученные сущности в change tracker. Это позволяет:
- автоматически фиксировать изменения объектов
- выполнять обновления без явного Attach
- обеспечивать identity resolution (один объект в памяти на одну запись в базе)
Но отслеживание имеет накладные расходы. Если запрос read-only и обновлять данные не нужно, то AsNoTracking() повышает производительность, отключая tracking целиком.
// Без отслеживания — быстрее для read-only сценариев
var customers = await context.Customers
.AsNoTracking()
.ToListAsync();
Хотя AsNoTracking() ускоряет работу, он создаёт тонкий, но важный побочный эффект: дублирующиеся сущности. Так как change tracker не занимается identity resolution, в памяти могут появляться несколько экземпляров одной и той же сущности.
Пример:
var orders = await context.Orders
.AsNoTracking()
.Include(o => o.Customer)
.Where(o => o.OrderDate > DateTime.Now.AddDays(-30))
.ToListAsync();
Если несколько заказов принадлежат одному и тому же пользователю, EF создаст отдельные экземпляры Customer для каждого заказа. В итоге это приводит к:
- лишнему потреблению памяти
- проблемам при сравнении объектов
- потере целостности графа объектов
Появляется AsNoTrackingWithIdentityResolution()
AsNoTrackingWithIdentityResolution() решает эту проблему и даёт баланс между:
- отсутствием tracking (производительность)
- сохранением identity resolution (один объект на сущность)
var orders = await context.Orders
.AsNoTrackingWithIdentityResolution()
.Include(o => o.Customer)
.Where(o => o.OrderDate > DateTime.Now.AddDays(-30))
.ToListAsync();
// Теперь несколько заказов с одним Customer будут ссылаться на один экземпляр
Как работает AsNoTrackingWithIdentityResolution():
- EF не добавляет сущности в change tracker
- во время материализации создаётся временная identity map
- сущности с одинаковым ключом указывают на один объект
- identity map удаляется после выполнения запроса
То есть мы получаем identity resolution при выполнении запроса, но без постоянных затрат tracking.
Если этот режим нужен часто, можно выставить его по умолчанию:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(connectionString)
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTrackingWithIdentityResolution);
}
Когда что использовать
- нужно обновлять, удалять или отслеживать изменения
- небольшой набор данных
- требуется автоматическое обнаружение изменений
- запрос read-only
- нет навигационных свойств или связанных сущностей
- критична максимальная производительность
- результат не содержит повторяющихся сущностей
- read-only запрос с Include/Join
- важна целостность графа объектов
- результаты содержат повторяющиеся сущности
- нужно сравнение объектов по ссылке
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17❤4
This media is not supported in your browser
VIEW IN TELEGRAM
Преподаватели берут то, с чем сами сталкиваются в повседневной работе Data Scientist, AI/ML Engineer, Data Engineer и Data Analyst, и превращают это в понятные практические упражнения.
Задачи в духе LeetCode, разбор живых кейсов, приёмы оптимизации. Всё, что позволяет уверенно чувствовать себя на собеседовании и дальше уже в команде.
После прохождения вы получите сертификат, который можно добавить в резюме.
В ближайшие 48ч курс доступен со скидкой 25% по промокоду «
BLACKFRIDAY25»: открыть курс на StepikPlease open Telegram to view this post
VIEW IN TELEGRAM
На Reddit обсуждают, каких возможностей не хватает C# и .NET. Автор поста поделился своим списком пожеланий, сформированным за годы работы с языком.
Среди предложений:
Автор подчёркивает, что C# ему нравится, но язык мог бы развиваться в сторону большей прозрачности и контроля над производительностью.
Какие функции вы хотели бы видеть в C# и dotnet?🤔
👉 @KodBlog
Среди предложений:
• статическое наследование как способ переиспользования логики без необходимости создавать экземпляры классов
• ключевое слово для гарантированного использования структур без распределения в куче
• принудительное инлайнинг методов, а не лишь намек компилятору
• ручной контроль над GC, похожий на подход Unity, чтобы критичный код не зависел от решений рантайма
• возможность создавать классы, которые полностью живут в unmanaged-памяти
• компактные ключевые слова для базовых типов, которые в .NET выглядят излишне громоздко
Автор подчёркивает, что C# ему нравится, но язык мог бы развиваться в сторону большей прозрачности и контроля над производительностью.
Какие функции вы хотели бы видеть в C# и dotnet?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🥴4🤨1