Библиотека шарписта | C#, F#, .NET, ASP.NET
22.2K subscribers
2.68K photos
41 videos
85 files
4.99K links
Все самое полезное для C#-разработчика в одном канале.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/b60af5a4

Для обратной связи: @proglibrary_feeedback_bot

РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
Download Telegram
📎 Делимся заметками красиво

Вы написали отличную заметку в Markdown в Obsidian, Notion или обычном редакторе, а теперь нужно отправить её коллеге или начальнику в Google Docs.

Копируете текст и... все форматирование слетает. Заголовки превращаются в решётки ###, списки ломаются, код выглядит убого.

Решение: md2cb

Простая утилита, которая конвертирует ваш Markdown в богатый HTML и кладёт в буфер обмена. Просто:
cat заметка.md | md2cb
# Ctrl+V в любое приложение


Есть флаг -e для быстрого редактирования:
md2cb -e  # открывает $EDITOR, конвертирует после сохранения


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

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

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Вопрос с собеса

Что такое абстракция в ООП?


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

Ключевое слово здесь — упрощение. Абстракция — ответ в канале с вопросами с собесов

Всё остальное — несущественные детали.

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

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

#dotnet_challenge
Please open Telegram to view this post
VIEW IN TELEGRAM
2
Архитектура ИИ-агентов: учим матчасть

Пока Microsoft развивает Semantic Kernel, индустрия стандартизирует паттерны на Python. Курс «Разработка ИИ-агентов» поможет понять принципы построения таких систем, независимо от вашего основного языка.

Что в программе:

— графовая оркестрация (LangGraph);
— работа с памятью и контекстом (RAG);
— мультиагентные протоколы.

Кодим на Python (нужны базовые знания), но полученные архитектурные скиллы универсальны. Первая лекция уже доступна.

Смотреть лекцию

Записаться на курс
🔥1
☕️ Веб-приложение для продуктивности

Разработчик запустил в продакшн своё веб-приложение для управления временем — The Coffee Timer. Проект реализует технику Pomodoro с кофейной эстетикой.

Приложение предлагает классический таймер Pomodoro с 25-минутными рабочими сессиями и визуализацией в виде анимированной кофейной чашки.

Бэк построен на .NET, фронт —React + TypeScript + Tailwind CSS. В качестве базы данных используется Supabase.

Хороший пример современного full-stack проекта с использованием .NET.

➡️ Попробовать приложение

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

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍121
🧑‍💻 Забытый await: от race condition до DoS-атаки

В C# ключевое слово async — это инструкция компилятору превратить метод в state machine. await отмечает точку логической приостановки. Всё просто: выполнение не должно продолжаться, пока результат не существует.

При await весь код выполняется синхронно, пока не достигнет I/O или функции, возвращающей Task. Если Task не завершён, происходит раскрутка кадра стека, и поскольку обрамляющие методы приостановлены до самого верха, поток может быть освобождён в пул потоков.

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

Если забыли await:
var task = GetDataAsync();
// забыли await
Use(task);


Это режим «запустил и забыл» (fire-and-forget). Последствия:

• выполнение продолжается немедленно
• зависимость не обеспечивается
• исключения выходят за пределы логического стека вызовов

Что может произойти с приложением

⚠️ Забытый await может привести к классическому состоянию гонки: код продолжает выполнение до завершения критической операции, например, проверки прав доступа, открывая окно для эксплуатации.

Атакующий может успеть получить доступ к данным между моментом начала проверки и её завершением.

⚠️ Когда исключения выходят за пределы логического стека вызовов, они могут быть проглочены без логирования. Это маскирует неудачные попытки аутентификации, SQL-инъекции или другие атаки.

⚠️ Истощение пула потоков как вектор DoS-атаки. При высокой нагрузке неправильное использование async/await приводит к истощению пула потоков. Злоумышленник может намеренно генерировать запросы, эксплуатирующие блокирующие операции.

➡️ Реальные атаки, уязвимости и практики безопасной разработки в Библиотеке хакера

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

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

#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍53
AI в экосистеме .NET: оставайтесь в тренде

Microsoft глубоко интегрировала AI (Semantic Kernel, Copilot) в нашу среду, но принципы работы агентов универсальны. Понимание того, как строятся цепочки ReAct или RAG, необходимо любому сеньору в 2026 году.

На курсе мы даём фундаментальную базу и практику (на Python-стеке, стандарте AI-индустрии). Эти знания позволят вам эффективно использовать AI-возможности в C
или создавать гибридные системы.

Архитектурный фокус:

— Оркестрация агентов (принципы применимы и к SK).
— Работа с векторными данными в SQL/NoSQL.
— Проектирование Stateful-систем с памятью.

Погрузиться в архитектуру AI
🤔1
📰 Дайджест недели

Уже прошла первая полноценная неделя февраля, собрали лучшее в один пост.

Git v2.53

Фриланс для разработчиков

Миграция с GitHub

Работа с LLM в .NET

Веб-приложение для продуктивности

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

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

#async_news
Please open Telegram to view this post
VIEW IN TELEGRAM
2
📎 Один файл превращается в полноценное приложение

В .NET 10 появилась фича, которая позволяет запускать C# код прямо из одного .cs файла без создания проекта.

Помимо этого туда можно подключать NuGet пакеты. Директива package в помощь:
#:package Newtonsoft.Json

using Newtonsoft.Json;

string json = "{\"name\": \"Иван\", \"age\": 30}";
var obj = JsonConvert.DeserializeObject<dynamic>(json);
Console.WriteLine($"{obj.name}, {obj.age} лет");


Первый запуск скачает пакет, дальше все мгновенно.

Можно прописать необходимую версию:
#:package Newtonsoft.Json@13.0.3


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

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

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
19🔥54🥱4
👍 Модификатор protected internal

В C# модификатор доступа protected internal открывает доступ к полю, методу или свойству из двух зон. Любые классы внутри той же сборки могут обращаться к такому члену напрямую.

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

Пример:
public class BaseClass
{
protected internal int SecretValue = 42;
}

Protected internal оказывается самым широким среди комбинированных, кроме public.

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

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
6🥱4🌚1
👀 Смотрим видео про URL

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

В видео подробно про пагинацию, query-параметры, фильтры, сортировки, поддомены, порты и пути с версионированием.

➡️ Подтянуть базу про URL

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

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

#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6😁1
⭐️ SQL Server в одном файле

LocalDB — это SQL Server в одном .mdf файле. Идеально для тестов, локальной разработки и инструментов. Создаётся одной командой, не требует установки сервера.

LocalDB — это облегчённая версия SQL Server, которая: работает в режиме пользователя, то есть без сервиса, хранит базу в одном .mdf файле, ведёт себя как настоящий SQL Server и не требует установки полноценного SQL Server.

Минимальный рабочий пример:
using Microsoft.Data.SqlClient;
using System.IO;

const string DatabaseName = "TestDatabase";
var databasePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"MyApp", "Data"
);

// Создаём директорию если её нет
if (!Directory.Exists(databasePath))
{
Directory.CreateDirectory(databasePath);
}

var dataFile = Path.Combine(databasePath, $"{DatabaseName}.mdf");
var logFile = Path.Combine(databasePath, $"{DatabaseName}_log.ldf");

// Безопасное экранирование для SQL
var escapedDbName = DatabaseName.Replace("]", "]]");
var escapedDataPath = dataFile.Replace("'", "''");
var escapedLogPath = logFile.Replace("'", "''");

var masterConnection = new SqlConnectionStringBuilder
{
DataSource = @"(localdb)\MSSQLLocalDB",
InitialCatalog = "master",
IntegratedSecurity = true,
TrustServerCertificate = true
}.ConnectionString;

var createDbQuery = $"""
IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = N'{escapedDbName}')
BEGIN
CREATE DATABASE [{escapedDbName}]
ON PRIMARY (
NAME = N'{escapedDbName}',
FILENAME = N'{escapedDataPath}'
)
LOG ON (
NAME = N'{escapedDbName}_log',
FILENAME = N'{escapedLogPath}'
)
COLLATE Latin1_General_100_CI_AI_SC_UTF8;
END
""";

using var conn = new SqlConnection(masterConnection);
await conn.OpenAsync();

using var cmd = new SqlCommand(createDbQuery, conn);
await cmd.ExecuteNonQueryAsync();

Console.WriteLine($"База данных создана: {dataFile}");


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

LocalDB работает под текущим пользователем Windows:

• Папка должна быть доступна на запись
• Не нужны права администратора
• Файлы принадлежат пользователю

Пакет: Microsoft.Data.SqlClient
Требует: LocalDB. Он входит в Visual Studio или SQL Server Express.

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

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
12👍1
🧑‍💻 Закон Хайрама: почему вы не можете изменить свой API

Формулировка закона:
При достаточном количестве пользователей API не имеет значения, что вы обещаете в контракте — все наблюдаемое поведение вашей системы станет чьей-то зависимостью.


Вы создали API. Написали документацию. Явно указали, что гарантируете, а что нет.
Но пользователи будут полагаться не только на задокументированное поведение, но и на:

• Порядок элементов в ответе
• Формат временных меток
• Текст сообщений об ошибках
• Время отклика
• Недокументированные эндпоинты
• Побочные эффекты
• Баги

И любое изменение этого может сломать чей-то прод.

Excel и ошибка 1900 года

В ранних версиях Excel был баг: 1900 год считался високосным, но таковым не являлся. Пользователи создали сложные таблицы, которые зависели от этого неправильного вычисления.

Microsoft не мог просто исправить баг — это сломало бы тысячи таблиц. Ошибка сохранялась до Excel 2003. Даже сейчас есть опция «Enable iterative calculation» для совместимости.

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

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍124
🤩 Свежее превью .NET

Microsoft выпустила первую предварительную версию .NET 11 с улучшениями во всех областях: рантайм, SDK, библиотеки, C#, ASP.NET Core, Blazor и .NET MAUI.

➡️ Библиотеки

• Поддержка Zstandard compression для эффективного сжатия
• BFloat16 — новый тип с плавающей точкой для ML-сценариев
• Улучшения ZipArchiveEntry для работы с архивами
• FrozenDictionary теперь поддерживает collection expressions

➡️ API и утилиты:

• Расширенная поддержка Rune в String, StringBuilder и TextWriter
• MediaTypeMap для определения MIME-типов
• API верификации HMAC и KMAC
• Создание жёстких ссылок
• DivisionRounding для режимов целочисленного деления
• Happy Eyeballs в Socket.ConnectAsync для быстрого подключения по IPv4/IPv6

➡️ Рантайм

• Runtime Async — улучшенная асинхронность на уровне рантайма
• CoreCLR на WebAssembly — полноценный рантайм в браузере
• Расширение интерпретатора
• JIT-оптимизации производительности
• GC Heap Hard Limit для 32-битных процессов
• Поддержка архитектур RISC-V и s390x

➡️ SDK

dotnet run теперь интерактивно выбирает целевой фреймворк и устройство
dotnet test поддерживает позиционные аргументы
dotnet watch — горячая перезагрузка для изменений в ссылках и настраиваемые порты

➡️ C# и F#

• C#: передача коллекций как аргументов
• C#: расширенная поддержка раскладки памяти
• F#: параллельная компиляция включена по умолчанию, ускорение компиляции вычислительных выражений, новые флаги --disableLanguageFeature и --typecheck-only для FSI.

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

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

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

#async_news
Please open Telegram to view this post
VIEW IN TELEGRAM
9🥰3👍2🤔1
⚡️ Почему IQueryable не должен покидать слой данных

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

IQueryable позволяет строить динамические SQL-запросы, выполняя фильтрацию на стороне БД, а не в памяти приложения:
var startDate = new DateTime(2023, 1, 1);

// Плохо: загружаем всё в память, затем фильтруем
var allRecords = context.Purchases.ToList();
var filtered = allRecords.Where(p => p.Date > startDate).ToList();

// Хорошо: фильтрация выполняется базой данных
var filtered = context.Purchases
.Where(p => p.Date > startDate)
.ToList();


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

Антипаттерн: распространение IQueryable.

Типичный сценарий — IQueryable передаётся через слои:
// Репозиторий
public class PurchaseRepository
{
public IQueryable<Purchase> GetAll() =>
_context.Purchases.AsQueryable();
}

// Сервис бизнес-логики
public class PurchaseService
{
public IQueryable<Purchase> GetActive() =>
_repository.GetAll().Where(p => p.Status == "Active");
}

// Контроллер
var userPurchases = _service.GetActive()
.Where(p => p.UserId == currentUserId);

// Представление
@foreach(var item in Model.Where(p => p.IsCompleted))
{
<!-- рендеринг -->
}


Проблемы:

• Логика доступа к данным размазана по всему приложению
• Нарушен принцип единственной ответственности
IQueryable наследует IEnumerable — код может не знать, что работает с запросом к БД
• Исключения в runtime, если EF не может преобразовать код в SQL
• Сложное тестирование и отладка

Решить эти проблемы можно, к примеру, паттерном спецификация, или, если спецификации избыточны, передавайте выражения:
public interface IPurchaseRepository
{
Task<List<Purchase>> FindAsync(Expression<Func<Purchase, bool>> predicate);
}

// Использование
var purchases = await _repository.FindAsync(
p => p.IsCompleted && p.UserId == currentUserId);


Запрос по-прежнему выполняется в БД, но логика доступа к данным инкапсулирована.

💬 Как бы вы решили эту проблему

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

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
8🤔5👍3
📷 Подборка вакансий для шарпистов

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

Middle/Senior .NET Developer — от 3 000 до 3 500 $. Удалёнка

C#/.NET-разработчик — Удалёнка

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

🐸 Библиотека шарписта
Please open Telegram to view this post
VIEW IN TELEGRAM
2
🌼 Бустим рабочее место за 10 шагов

Удаленка — это не только про свободу выбора места работы, но и про умение создать условия для продуктивности.

➡️ В карточках 5 советов по обустройству рабочего места, а остальные в статье.

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

🐸 Библиотека шарписта
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1