csharpproglib | Unsorted

Telegram-канал csharpproglib - Библиотека шарписта | C#, F#, .NET, ASP.NET

23284

Все самое полезное для C#-разработчика в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/b60af5a4 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead

Subscribe to a channel

Библиотека шарписта | C#, F#, .NET, ASP.NET

🔎 Подборка вакансий для шарпистов

Fullstack .NET / C# Developer (Middle/Senior) — 3 000 —‍ 4 500 $, удалёнка.

Middle Unity (С#) developer — от 1 500 до 2 700 $, удалёнка.

C# backend-разработчик в команду Security — офис или гибрид в Москве.

➡️ Еще больше топовых вакансий — в нашем канале C# Jobs

🐸 Библиотека шарписта

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🔄 .NET 11 Preview 2

Вышел второй превью .NET 11. Пока это не финальный релиз, но уже есть что посмотреть.

Самое заметное в этом превью — работа над производительностью на нескольких уровнях одновременно.

• В рантайме появился Runtime Async V2.

Это переработанная реализация асинхронности на уровне самого рантайма, не на уровне компилятора. Цель — убрать лишние аллокации и сделать работу async/await дешевле по ресурсам.

• SDK стал немного меньше.

Установщики для Linux и macOS сократились в размере. Плюс обновили анализаторы кода и добавили новые предупреждения при сборке.

• F# в этом превью получил несколько практичных вещей.

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

Упростили иерархии DIM-интерфейсов, добавили директиву #elif и функцию partitionWith для коллекций.

• В Entity Framework Core добавили поддержку LINQ операторов MaxBy и MinBy. Для SQL Server появилась поддержка DiskANN векторных индексов и VECTOR_SEARCH().

• MAUI тоже не обошли стороной. Улучшили работу карт, ускорили TypedBinding, добавили аннотации неизменяемости для Color и Font. Для Android теперь минимально требуется API 24.

➡️ Источник

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#пульс_индустрии

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

Часовая готовность: создаём ИИ-агента в прямом эфире

В 19:00 МСК в рамках нашего курса «Разработка AI-агентов» стартует вебинар «ИИ-агенты в продакшене: от хайпа к деньгам». Спикер — Полина Полунина, руководитель AI-направления в Альфа-Банке.

Будет live-демо работающего агента, реальные метрики из корпоративной среды и честный разбор архитектурных граблей — без воды и «успешного успеха».

Всем зрителям эфира дадим эксклюзивный промокод AGENTS на скидку 10 000 ₽ на любой тариф курса.

👉 Занять место на вебинаре

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

📋 Один и тот же рынок, но разные шансы

Кандидат с рекомендацией получает оффер в 4 раза чаще, чем тот, кто откликнулся в холодную. Сбер говорит, что треть сотрудников пришли именно так. И это не исключение — это уже норма для крупных IT-компаний.

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

➡️ Как устроиться по рекомендации и где искать реферальные программы

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

👨‍💻 Протокол против AI слопа в вебе

Есть потрясающий проект, который пытается решить одну из главных проблем современного интернета: как узнать, создан ли контент человеком или это просто сгенерированный AI?

Как работает доверие

Не нужно доверять всему интернету сразу. Выбираете несколько сайтов, которым уже доверяешь.

Потом система ищет все сайты, которые эти люди одобрили. Это 1 хоп. Потом сайты, которые одобрили они. Это 2 хопа. И так далее.

Если видите сайт, который находится на расстоянии 1-2 хопа от человека, которому вы доверяете, то это реальный контент с высокой вероятностью.

Расстояние визуализируется цветом: зелёный (0-1 хоп), жёлтый (2), оранжевый (3+).

Вы публикуете на своём сайте JSON файл:

{
"version": "0.1.1",
"url": "https://example.com",
"vouches": [
{
"url": "https://trusted-person.com",
"vouched_at": "2026-01-15"
}
]
}


И в <head> добавляете:
<link rel="human-json">


Браузерное расширение видит эту ссылку и проверяет: есть ли у этого человека люди, которые его одобрили. Если есть, и они находятся на расстоянии 1-2 хопа от Вас, сайт получает зелёный индикатор.

Если Вы добавите human.json сейчас, Вы будете в первой волне. Это как было с SSL 15 лет назад.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#garbage_collector

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

💥 Открытый вебинар | ИИ-агенты в продакшене: от хайпа к деньгам

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

Полина Полунина, руководитель AI-направления Альфа-Банка, расскажет честно:

▪️ Чем агент отличается от «просто GPT с промптом» и когда бизнесу достаточно обычного LLM
▪️ 3 реальных кейса из корпоративной среды: что взлетело, а что нет
▪️ Live-демо работающего агента
▪️ ТОП-5 граблей, на которые наступают команды при внедрении

⏱️ 10 марта в 19:00 (МСК)

🎁 Участники получат промокод на скидку на самый полный курс по ИИ-агентам

👉 Регистрируйся

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🔎 Microsoft Foundry: февраль 2026

В феврале Foundry получил существенный апдейт. Вышли Claude 4.6 от Anthropic и Grok 4.0 от xAI, Agent Framework достиг release candidate с серьезными изменениями, и все SDK переходят на единую REST архитектуру.

Новые модели

Claude Opus 4.6 и Claude Sonnet 4.6 теперь доступны в Foundry. Opus для сложного рассуждения, Sonnet примерно того же уровня, но дешевле. Оба поддерживают миллион токенов контекста и 128K токенов в ответе.

Grok 4.0 от xAI стал GA. Одновременно вышла Grok 4.1 Fast для классификации и маршрутизации без рассуждений: 0.20 долларов за миллион на вход.

GPT-Realtime-1.5 и GPT-Audio-1.5 улучшили следование инструкциям на 7% и точность транскрипции на 10%.

FLUX.2 Flex специально для UI дизайна с текстом.

Agent Framework: Release Candidate и HITL

Agent Framework вышел в 1.0.0rc1 с замороженным API. Общий выпуск уже рядом, но есть разрывающие изменения.

Главные перемены:

• Учетные данные теперь используют Azure Identity вместо токена
• Сессии вместо потока
• response.messages вместо response.text
create_version() вместо create()
• Предварительные операции в подкаталоге .beta

REST API v1 GA

Foundry REST API v1 теперь production-ready. Все основные эндпоинты заморожены: чаты, ответы, встраивания, файлы, тонкая настройка, модели, хранилища векторов.

Если ваш SDK еще в pre-release, можете запросить REST API напрямую.

SDK обновления

.NET 2.0.0-beta.1: ImageBasedHostedAgentDefinition объединили с HostedAgentDefinition.

Foundry Local и VS Code

Foundry Local теперь поддерживает большие мультимодальные модели полностью автономно без облака.

AI Toolkit for VS Code v0.30.0 добавил Tool Catalog для поиска инструментов, Agent Inspector для дебага с F5 breakpoints и переделанный Agent Builder.

В марте SDK будут общедоступны. Обновитесь к RC сейчас, если используете.

➡️ Блог разработчиков

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#async_news

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🤔 Вопрос с собеса

Классика интервью:

Что такое readonly struct и чем он отличается от обычной структуры


На собесе часто ловят на вопросе «когда использовать». Многие говорят просто «для безопасности», но это неправильный ответ.

Правильный ответ, который ждут на собесе ждёт только вас в нашем канале с вопросами с собесов

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#dotnet_challenge

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

📝 Вытащить текст из PDF на C#

Иногда нужно просто достать текст из PDF — для скрипта, личного инструмента или быстрой автоматизации под себя. Руками копировать лень, особенно если файлов несколько. Вот способ сделать это на C# без лишних телодвижений.

Что использовать

Библиотека Free Spire.PDF для .NET. Устанавливается через NuGet одной командой и не требует ничего стороннего — ни ридеров, ни внешних утилит.

Install-Package FreeSpire.PDF


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

Базовый пример — одна страница:
PdfDocument doc = new PdfDocument();
doc.LoadFromFile("Sample.pdf");

PdfPageBase page = doc.Pages[1]; // вторая страница
PdfTextExtractor extractor = new PdfTextExtractor(page);
PdfTextExtractOptions options = new PdfTextExtractOptions { IsExtractAllText = true };

string text = extractor.ExtractText(options);
File.WriteAllText("output.txt", text);

doc.Close();


Весь документ сразу:
StringBuilder allText = new StringBuilder();
foreach (PdfPageBase page in doc.Pages)
{
var extractor = new PdfTextExtractor(page);
var options = new PdfTextExtractOptions { IsExtractAllText = true };
allText.AppendLine(extractor.ExtractText(options));
}
File.WriteAllText("output.txt", allText.ToString());


Что ещё умеет библиотека

Зашифрованные PDF открываются передачей пароля прямо в LoadFromFile. Если нужен текст только из конкретной области страницы — задаёшь прямоугольник через ExtractArea в точках (1 point = 1/72 дюйма).

Для таблиц есть отдельный PdfTableExtractor, который возвращает данные в виде массива. Сканы и нечитаемые PDF решаются через Spire.OCR в связке с основной библиотекой.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

👨‍💻 NuGet стал удобнее

Разработчик запустил nugetz.dev — альтернативный интерфейс для поиска по реестру NuGet.

Стандартный поиск на nuget.org работает, но медленно и неудобно. Когда выбираешь библиотеку, хочешь быстро понять: пакет живой, как давно обновлялся, насколько популярен. Сейчас это занимает лишнее время.

Nugetz решает именно это. Тот же реестр, но с чистым интерфейсом, быстрой выдачей и без лишнего шума на экране. Без регистрации и рекламы.

Идея пришла от npmx — похожего инструмента для npm-экосистемы. Rodrigo просто спросил себя, почему у .NET такого нет, и сделал.

➡️ Попробовать

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#пульс_индустрии

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

😎 Подборка вакансий для шарпистов

C# backend-разработчик в команду Security — Офис/гибрид в Москве

Backend Engineer — от 175 000 до 325 000 ₽, удалёнка

C#/.NET разработчик — от 350 000 ₽, удалёнка

Бустер — Удалённо в любом городе мира.

➡️ Еще больше топовых вакансий — в нашем канале C# Jobs

🐸 Библиотека шарписта

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#garbage_collector

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🔌 Пишите интерфейс так, чтобы не объяснять

Хороший код легко использовать правильно — и сложно использовать неправильно. Это важно при проектировании API: даже внутреннего.

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

Вот на что стоит обращать внимание:

Понятен ли смысл метода. Название должно говорить само за себя без комментария над функцией и без погружения в реализацию.

Если приходится читать тело метода, чтобы понять что он делает, значит имя плохое.

Предсказуемо ли поведение. Метод с одинаковыми параметрами должен возвращать одинаковый результат.

Скрытые побочные эффекты и неочевидные состояния — прямой путь к багам, которые воспроизводятся через раз.

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

ProcessData(bool flag1, bool flag2);


Явные типы — намерение читается сразу:
ProcessData(ProcessMode mode, ValidationOptions options);


Исключения или типы результата. Исключения созданы для исключительных ситуаций, а типы результата для ожидаемых ошибок.

Смешивать их = заставлять пользователя угадывать, что пойдёт не так и в каком виде.

Минимум обязательных параметров. Чем больше параметров нужно передать для базового вызова, тем выше порог входа.

Если для простого случая нужно заполнить пять аргументов, скорее всего интерфейс нуждается в умных значениях по умолчанию или отдельном упрощённом методе.

Удобный интерфейс это уважение к тем, кто будет с ним работать. И к себе через полгода, когда придётся вернуться к этому коду.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#il_люминатор

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

👨‍💻 Генерируйте curl прямо из кода

HttpClient.CurlDelegatingHandler — это обработчик в пайплайне HttpClient, который перехватывает запрос и возвращает готовую curl-команду в заголовке ответа. Никакой дополнительной логики писать не нужно.

Поддерживаются GET, POST, PUT и DELETE.

Как подключить:

dotnet add package HttpClient.CurlDelegatingHandler --version 1.0.0-alpha.1


Как использовать

Передаёте CurlDelegatingHandler при создании клиента. Чтобы запрос не ушёл в сеть, добавляете заголовок CanSend: False. Curl-команда придёт обратно в заголовке outputCurl.

using System.Text;
using CurlGenerator;

string url = "https://jsonplaceholder.typicode.com/posts";
string jsonPayload = @"{""title"": ""New Post"", ""body"": ""This is the body"", ""userId"": 1}";
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");

var httpClient = new HttpClient(new CurlDelegatingHandler());
httpClient.DefaultRequestHeaders.Add(Settings.CanSend, "False");

var result = await httpClient.PostAsync(url, content);
string outputCurl = result.Headers.GetValues(Settings.OutputCurl).FirstOrDefault();

Console.WriteLine(outputCurl);


Вывод:
curl -X POST 'https://jsonplaceholder.typicode.com/posts' -H 'Content-Type: application/json' ...


DelegatingHandler встраивается в цепочку обработчиков HttpClient. Вместо того чтобы отправлять запрос по сети, он его перехватывает, строит из него curl-строку и возвращает её в заголовке ответа. Вся логика изолирована в одном месте.

➡️ Затестить пакет

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

📄 Автоматическое удаление персональных данных из документов на C#

Рабочие документы почти всегда содержат что-то личное. Имена, номера паспортов, банковские счета, налоговые идентификаторы — всё это регулярно оседает в PDF-файлах и других документах.

Cloudmersive предлагает DLP API с поддержкой .NET, который работает через AI-модель с наложением сетки на документ.

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

Установка:

Install-Package Cloudmersive.APIClient.NETCore.DLP -Version 1.1.0


Сам вызов выглядит так:
using Cloudmersive.APIClient.NETCore.DLP.Api;
using Cloudmersive.APIClient.NETCore.DLP.Client;
using Cloudmersive.APIClient.NETCore.DLP.Model;

Configuration.Default.AddApiKey("Apikey", "YOUR_API_KEY");

var apiInstance = new RedactApi();
var body = new DlpDocumentRedactionRequest();

DlpDocumentRedactionResponse result = apiInstance.RedactDocument(body);


В ответе приходит отредактированный документ и набор флагов Contains* — по одному на каждый тип данных. Это удобно, если нужно не просто скрыть данные, но и зафиксировать факт их присутствия в документе для аудита. Отдельно возвращается список страниц, на которых были внесены правки.

Для использования нужен API-ключ Cloudmersive — регистрация на их сайте, есть бесплатное использование.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

⚙️ Лямбды с захватом переменных: скрытые аллокации на горячем пути

Один из способов незаметно нагрузить хип — захватить локальную переменную внутри лямбды:

int threshold = 10;
var query = items.Where(x => x > threshold);


Код читается легко. Но когда лямбда захватывает threshold, компилятор может сгенерировать объект-замыкание для хранения этого состояния. Microsoft явно документирует static-лямбды как способ запретить захват и предотвратить лишние аллокации.

Почему это проблема

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

Как исправить

Если захват не нужен, скажите об этом явно:
var query = items.Where(static x => x > 10);


Или вынесите логику в отдельный метод:
static bool IsAbove(int x, int threshold) => x > threshold;


Если лямбда находится на горячем пути, смотрите на неё глазами performance-инженера, а не просто читателя кода. Захват состояния это повод насторожиться.


📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#il_люминатор

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

☝️ Уже сегодня: ИИ-агенты в продакшене — инженерный подход к интеграции LLM

Индустрия активно обсуждает потенциал нейросетей, способных автоматизировать бизнес-процессы и заменить целые отделы. Однако реальное внедрение агентов в production вскрывает серьёзные проблемы: разработчикам приходится бороться с непредсказуемыми галлюцинациями моделей, нестабильными API и сложной интеграцией в существующую архитектуру.

Сегодня в 19:00 МСК в рамках нашего курса «Разработка AI-агентов» мы проведём открытый вебинар «ИИ-агенты в продакшене: от хайпа к деньгам». Спикер — Полина Полунина, руководитель AI-направления в Альфа-Банке. Будем говорить о нейросетях с позиции жёсткой инженерии.

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

Тем, кто придёт на эфир, дадим промокод AGENTS на скидку 10 000 ₽ на любой тариф курса.

👉 Занять место на вебинаре

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

💡 Консольный интерфейс за 5 минут

SharpConsoleUI — это библиотека для .NET, которая позволяет строить полноценный оконный интерфейс прямо в терминале.

Несколько окон одновременно, модальные диалоги, фокус, мышь, клавиатура. Всё то, что обычно ждёшь от GUI-фреймворка, но работает в консоли.

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

Самый простой вариант:

var windowSystem = new ConsoleWindowSystem(RenderMode.Buffer);
var window = new Window(windowSystem)
{
Title = "Hello World",
Width = 50,
Height = 15
};
windowSystem.AddWindow(window);
windowSystem.Run();


Начиная с версии 2.0 появился fluent API:
var window = new WindowBuilder(windowSystem)
.WithTitle("Modern Hello World")
.WithSize(50, 15)
.Centered()
.WithColors(Color.DarkBlue, Color.White)
.Build();


Прямой вывод в консоль в этой библиотеке нельзя использовать — он ломает рендеринг. Вместо этого есть встроенный сервис логирования, который пишет в файл. Включается через переменные окружения:
export SHARPCONSOLEUI_DEBUG_LOG=/tmp/consoleui.log
export SHARPCONSOLEUI_DEBUG_LEVEL=Debug


Библиотека поставляется с готовыми элементами управления. Среди них разметочный контрол на основе Spectre.Console, кнопки, чекбоксы, многострочный редактор текста с прокруткой, дерево для иерархических данных, список с выбором и табличная сетка.

➡️ Репозиторий

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🛠 MCP C# SDK v1.0

Стабильная версия пакета разработчика принесла полезные фичи для интеграции ИИ в .NET.

OAuth теперь проще. Сервер может хранить метаданные тремя способами, пакет найдёт сам.

Инструменты теперь получают иконки. Настраивается через атрибут:

[McpServerTool(IconSource = "https://example.com/icon.svg")]
public static string GetWeather(string city) { }


Инструменты в запросах к модели

Сервер может включить инструменты в запрос к модели языка, и она их вызовет. Модель выполняет инструмент, сервер обрабатывает результат и отправляет обратно. Это может повторяться несколько раз.

На клиенте объявляйте поддержку:
var mcpClient = await McpClient.CreateAsync(
new HttpClientTransport(new() { Endpoint = new Uri("http://localhost:6184") }),
clientOptions: new()
{
Capabilities = new ClientCapabilities
{
Sampling = new SamplingCapability { Tools = new SamplingToolsCapability {} }
}
});


На сервере просто передавайте инструменты в запрос:
Tool rollDieTool = new Tool()
{
Name = "roll_die",
Description = "Rolls a six-sided die and returns 1-6."
};


Долгоживущие запросы

Раньше при разрыве соединения нужно было пересоединяться. Теперь сервер отправляет пустое событие с ID и может закрыть соединение. Клиент переподключится через этот ID.

На сервере:
builder.Services.AddDistributedMemoryCache();
builder.Services.AddMcpServer()
.WithHttpTransport()
.WithDistributedCacheEventStreamStore()
.WithTools<MyTools>();


В обработчик вызовите:
await context.EnablePollingAsync(retryInterval: TimeSpan.FromSeconds(5));


Задачи для долгих операций

Задачи хранят результаты надёжно и позволяют опрашивать состояние, получать результаты и отменять работу. Могут быть в состояниях: работает, требуется ввод, завершена, ошибка, отменена.

На сервере:
var taskStore = new InMemoryMcpTaskStore();
builder.Services.AddMcpServer(options => { options.TaskStore = taskStore; })
.WithHttpTransport();


Инструменты автоматически поддерживают задачи если возвращают Task:
[McpServerTool(TaskSupport = ToolTaskSupport.Required)]
public static async Task<string> ProcessData(int count, CancellationToken ct)
{
await Task.Delay(TimeSpan.FromSeconds(8), ct);
return $"Processed {count} records.";
}


На клиенте:
var result = await client.CallToolAsync(
new CallToolRequestParams
{
Name = "processDataset",
Task = new McpTaskMetadata { TimeToLive = TimeSpan.FromHours(2) }
});

var completedTask = await client.PollTaskUntilCompleteAsync(result.Task.TaskId);


Версия 1.0 это полноценная платформа для ИИ интеграции в .NET.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#async_news

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🖥 Первый дайджест весны

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

Cake 6.0.0 вышел

Спам тимлидам, фейковые офферы и приукрашенное резюме

Merge conflict для календаря

NuGet стал удобнее

Noundry готова к бою

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#async_news

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

👨‍💻 Кэширование в три слоя — спасение базы данных

База данных имеет лимит количества запросов в секунду, который она может обработать. При миллионах запросов в час этот лимит будет достигнут независимо от того, насколько хорошо написан код. Решение одно: кэшировать агрессивно.

Неправильный подход это кэшировать все и везде без логики. Правильный подход это иметь стратегию кэширования с разными слоями.

Первый слой: память приложения

MemoryCache в .NET работает очень быстро, потому что данные лежат в памяти одного процесса. Здесь кэшируются часто запрашиваемые данные с коротким временем жизни. Профили пользователей, настройки, статические справочники. TTL может быть 30 секунд или минута.

Второй слой: распределенный кэш

Redis или Memcached. Когда приложение запущено на нескольких контейнерах, они должны видеть одни и те же данные. Если один контейнер кэшировал профиль пользователя, остальные должны получить его без запроса в БД.

Третий слой: кэширование ответов

Некоторые API ответы не зависят от пользователя и могут быть закэшированы целиком. Если GET /api/countries возвращает список стран, это можно кэшировать на час, потому что страны не меняются часто.

На практике такая архитектура может снизить нагрузку на базу данных на 80 процентов. Просто потому, что большинство запросов идут в кэш, а не в БД.

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

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#il_люминатор

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

📎 JsonSerializerOptions в каждом запросе это бомба замедленного действия

Вы оптимизировали базу данных. Ничего не изменилось. Оптимизировали сетевые вызовы. Всё ещё медленно.

Оказалось, приложение создаёт новый JsonSerializerOptions в каждом запросе. Это уничтожает встроенный кеш метаданных System.Text.Json и превращает JSON сериализацию в дорогую операцию, которая повторяется сотни раз в секунду под нагрузкой.

Почему это так дорого

JsonSerializerOptions это не просто настройки. Это место, где System.Text.Json хранит кэшированные метаданные о том, как сериализовать и десериализовать типы.

Каждый новый экземпляр JsonSerializerOptions начинает с пустого кеша. System.Text.Json должна заново анализировать тип, строить информацию о сериализации, кешировать её. Потом запрос закончился и всё выбросилось.
Следующий запрос приходит. Новый экземпляр. Пустой кеш снова. Всё сначала.

Microsoft так серьёзно относится к этому, что добавили анализатор CA1869, который явно предупреждает: не создавайте JsonSerializerOptions локально в горячих путях.

Ошибка выглядит безобидно:

string ToJson(object value)
{
var options = new JsonSerializerOptions(JsonSerializerDefaults.Web)
{
WriteIndented = false
};
return JsonSerializer.Serialize(value, options);
}


Под нагрузкой это выглядит как:

• CPU растёт без видимых причин
• Задержка становится нестабильной, p99 скачет
• Профилер показывает JSON сериализацию как горячую точку
• А вы не понимаете почему, если оптимизировали всё остальное

Создайте JsonSerializerOptions один раз при старте приложения и переиспользуйте везде:
public static class JsonDefaults
{
public static readonly JsonSerializerOptions Web = new(JsonSerializerDefaults.Web)
{
WriteIndented = false,
Converters = { new JsonStringEnumConverter() }
};
}

Используем кеш, никаких затрат
return JsonSerializer.Serialize(payload, JsonDefaults.Web);


Одна переменная, кеш остаётся тёплым, производительность стабильной.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#il_люминатор

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

👨‍💻 Noundry готова к бою

Noundry это набор инструментов и библиотек для .NET разработки. В состав входит Tuxedo, Tailbreeze, Assertive, Authnz, Engine, AI Gateway и другие компоненты.

Разработчик годами решал одни и те же задачи за корпоративными файрволами. Классическое энтерпрайз консультирование: сложные системы, высокие ставки, миллионы транзакций. Код был хороший, но никто не видел. Результат работы жил за файрволом.

Теперь он решил поделиться тем, что наработал за два десятилетия. Выложил в публичное и начал строить сообщество вокруг этого.

➡️ Веб-сайт

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#async_news

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

👍 На курсе по контролируемой разработке AI-агентов мы будем разбирать ровно то, о чём говорит Владислав в голосовом, но уже в формате системной практики.

📅 Старт курса — 20 апреля.

Если хотите разобраться, как строить управляемые агентные системы:
➡️ Присоединяйтесь.

P.S. С первого занятия будет практика: код и разбор реальных ошибок, а не только теория.

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

⚙️ Базовый класс в C#: когда чистая архитектура становится проблемой

Всё начинается разумно. В нескольких сервисах повторяется одна логика — контекст БД, аудит, логирование. Выносишь в базовый класс. Код короче, дублирования нет.

Проходит полгода. Простой юнит-тест поднимает глобальную шину событий и запускает рефлексию. Никто не просил. Просто создали экземпляр репозитория.

Что происходит в конструкторе:

public abstract class RepositoryBase<TEntity>
{
protected RepositoryBase(DbContext context)
{
Context = context;
ApplyEntityConfiguration(); // рефлексия
SubscribeToAuditEvents(); // подписка на события
}
}


Производный класс просто вызвал base() — и получил в нагрузку поведение, которое не запрашивал. Это невидимая связанность: поведение определяется не сигнатурой, а тем, что спрятано в цепочке наследования.

Особый случай — глобальное состояние

Статический инициализатор внутри базового класса меняет сериализацию для всего приложения при первой загрузке любого наследника. Не локально — глобально. Молча.

Наследование vs композиция

Глубокое дерево: RepositoryBase → MongoBase → AuditableBase → ProductRepository. Четыре уровня. Поведение на каждом. Ничего не видно на месте вызова.

Декоратор решает то же самое явно:
public class AuditingRepository : IProductRepository
{
private readonly IProductRepository _inner;
private readonly IAuditService _audit;

public async Task<Product> GetByIdAsync(Guid id)
{
await _audit.LogAccessAsync(id);
return await _inner.GetByIdAsync(id);
}
}


Каждый слой делает одну вещь. Зависимости видны. Убрать логирование можно не трогая репозиторий.

Глобальная конфигурация — в точку запуска

Если что-то влияет на всё приложение, оно должно жить в Program.cs, а не в базовом классе, который загружается неизвестно когда.

Базовый класс становится проблемой, когда берёт на себя слишком много. В этот момент он перестаёт быть абстракцией и превращается в объект бога.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🛠 Жизни зависимостей в ASP.NET

Одна из самых частых причин непредсказуемого поведения приложений на ASP.NET Core — неправильно выбранное время жизни сервиса. Проблема тихая: приложение запускается, тесты проходят, а в продакшне начинается что-то странное.

Три режима, которые нужно знать

В ASP.NET у каждого сервиса есть время жизни экземпляра.

Transient. Новый экземпляр создаётся каждый раз, когда сервис запрашивается из контейнера. Подходит для лёгких, stateless-сервисов без общего состояния.

Scoped. Один экземпляр на HTTP-запрос. Все зависимости внутри одного запроса получают один и тот же объект. Это стандартный выбор для большинства сервисов в веб-приложениях.

Singleton. Один экземпляр на всё время жизни приложения. Создаётся один раз и переиспользуется во всех запросах.

Где ломается

Самая распространённая ошибка — инжектировать Scoped-сервис в синглтон. Выглядит невинно, но это называется captive dependency, и ASP.NET даже выбросит исключение при старте, если включена валидация.

// Так делать не надо
public class MySingleton
{
private readonly IScopedService _scoped;

public MySingleton(IScopedService scoped) // Проблема здесь
{
_scoped = scoped;
}
}


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

Если нужен Scoped-сервис внутри синглтона, используйте IServiceScopeFactory:
public class MySingleton
{
private readonly IServiceScopeFactory _scopeFactory;

public MySingleton(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}

public void DoWork()
{
using var scope = _scopeFactory.CreateScope();
var scoped = scope.ServiceProvider.GetRequiredService<IScopedService>();
scoped.Execute();
}
}


И включите валидацию зависимостей в dev-окружении — ASP.NET поймает большинство проблем ещё при запуске.

builder.Host.UseDefaultServiceProvider(options =>
{
options.ValidateScopes = true;
options.ValidateOnBuild = true;
});


Если не уверены в выборе, начинайте со Scoped. Для веб-приложений это безопасный дефолт. Singleton используйте только тогда, когда явно нужно общее состояние, и убедитесь, что сервис действительно thread-safe. Transient подходит для простых утилит без состояния.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🗓 Merge conflict, но для календаря

В git есть автоматический резолв конфликтов. Теперь такое есть и для встреч — Microsoft Copilot в Outlook и Teams умеет сам переносить встречи, если в расписании возник конфликт.

Работает для личных встреч и 1:1. Групповые звонки, встречи длиннее 5 часов и повторяющиеся реже раза в месяц — пока не поддерживаются. Но для большинства рабочих 1:1 — уже удобно.

➡️ Источник

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#async_news

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

🤔 Спам тимлидам, фейковые офферы и приукрашенное резюме

IT-рынок 2026 года — это не конкурс честных и талантливых. Компании говорят об экологичной культуре, а сами гостят после четырёх этапов отбора.

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

➡️ Узнать приёмы тех, кто смог

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#sharp_view

Читать полностью…

Библиотека шарписта | C#, F#, .NET, ASP.NET

💻 Утечки памяти в .NET

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

Главный инструмент .NET для освобождения ресурсов — интерфейс IDisposable и его асинхронный вариант IAsyncDisposable. Если объект реализует один из них, значит он держит что-то важное: файловый дескриптор, сетевое соединение, неуправляемую память.

Без using объект останется жить до следующего прохода GC, а ресурс под ним — ещё дольше:

// Утечка: поток не закроется при исключении
var stream = new FileStream(path, FileMode.Open);

// Правильно: using гарантирует закрытие даже при исключении
using var stream = new FileStream(path, FileMode.Open);


Для асинхронных ресурсов — await using:
await using var resource = GetAsyncDisposable();


Что проверить в коде

Потоки. Каждый Stream, StreamReader, StreamWriter должен быть обёрнут в using. Без этого файловые дескрипторы накапливаются.

HttpClient. Один из самых частых источников проблем. Его нельзя создавать на каждый запрос, так как это исчерпывает пул сокетов.

Крупные аллокации. Массивы, буферы, большие строки — если они создаются в цикле, это быстро давит на GC. Здесь помогает ArrayPool<T> или System.Buffers.

var pool = ArrayPool<byte>.Shared;
byte[] buffer = pool.Rent(4096);
try
{
// работа с буфером
}
finally
{
pool.Return(buffer);
}


Object Pooling. Если объекты дорогие в создании и используются часто — ObjectPool<T> из Microsoft.Extensions.ObjectPool снижает нагрузку на аллокатор.

Простое правило: если тип реализует IDisposable, оборачиваем его в using. Остальное — профилировщик покажет.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#il_люминатор

Читать полностью…
Subscribe to a channel