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

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

Kanalga Telegram’da o‘tish

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

Ko'proq ko'rsatish
2025 yil raqamlardasnowflakes fon
card fon
22 356
Obunachilar
-624 soatlar
-327 kunlar
-14630 kunlar
Postlar arxiv
🧑‍🎓 Диплом = 15% к зарплате Диплом в IT вещь нестабильная. Одним подавай три профильных, чтобы устроиться, другие косо взглянут на любой диплом, который не из МФТИ. В карточках собрали факты про эту корочку. Листайте и проверяйте сколько вам можно накинуть за диплом. ➡️ Полный материал 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта
Hammasini ko'rsatish...
2🥰 2
Photo unavailableShow in Telegram
🎓 Твой опыт стоит дорого — стань экспертом Proglib Academy Чувствуешь, что накопил достаточно знаний, чтобы делиться ими с другими? Мы ищем сильных практиков, которые хотят попробовать себя в роли: — преподавателей; — авторов курсов; — наставников. Это возможность не только монетизировать экспертизу, но и прокачать личный бренд, структурировать собственные знания и вырастить новое поколение специалистов. 👉 Заполни короткую анкету
Hammasini ko'rsatish...
✏️ Вопрос с собеса Админ принёс актуальный вопрос, который ему задали вчера на собеседовании. Чем отличаются IQueryable<T> и IEnumerable<T> помимо синтаксиса? Можете оставить свой ответ в комментариях и сравнить его с нашим. 👉 Посмотреть ответ в нашем канале с задачами 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #dotnet_challenge
Hammasini ko'rsatish...
Photo unavailableShow in Telegram
📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #garbage_collector
Hammasini ko'rsatish...
💯 24😁 10
Photo unavailableShow in Telegram
😁 Он вам не веб-сервис Вы замечали, что Windows работает не так, как раньше? Это всё из-за новомодных ИИ и веб-элементов. Первое пишет, а второе лагает. Наткнулись на видео, где всё это выпиливают из актуальной Windows 11. Результат вас не порадует, но зато вы узнаете на что конкретно жаловаться в Microsoft. ➡️ Смотреть видео 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #sharp_view
Hammasini ko'rsatish...
👍 3 2🥰 1
Photo unavailableShow in Telegram
💻 Свежий контент для Copilot Проблема с Copilot: он не знает о новых штуках вроде Agent Framework. Решение от Microsoft: MCP сервер дает доступ к свежей .NET-документации прямо в инструментах разработки. Сервер передает Copilot актуальные данные: гайды, код, уроки. Идеально для .NET 10, Aspire или оптимизации старых приложений. Контекст адаптируется под код. ➡️ Как всё это настроить 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #sharp_view
Hammasini ko'rsatish...
👍 3
Photo unavailableShow in Telegram
🔍 Подборка ИИ-инструментов для поиска работы за рубежом На сайте Библиотеки программиста вышла обновлённая подборка AI сервисов для тех, кто хочет искать работу в IT за пределами своей страны. Вместо того чтобы пытаться вручную тянуть LinkedIn, job‑борды и подготовку к интервью, имеет смысл собрать для себя связку из нескольких AI сервисов и переложить на них максимум рутины. ➡️ Список сервисов 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта
Hammasini ko'rsatish...
2🥱 2
💲 Дорогое логирование только в dev Иногда нужно навесить на код тяжёлую отладочную диагностику, но в проде за неё платить не хочется. Для таких случаев есть атрибут Conditional, который полностью выкидывает вызовы метода из Release сборки. Базовый пример:
[Conditional("DEBUG")]
public static void Trace(string message)
{
    Console.WriteLine("[TRACE] " + message);
}
Это удобно для временного трассинга, сложных проверок и дорогих assert’ов, которые нужны только при разработке. Debug.Assert и Debug.WriteLine работают так же — они помечены [Conditional("DEBUG")], поэтому автоматически исчезают из релизной сборки. 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #il_люминатор
Hammasini ko'rsatish...
💯 8 4🥱 1
⚙️Паттерн пагинации и фильтрации через один запрос и нормальные DTO Пагинация в API часто превращается либо в магию репозиториев, либо в жуткий копипаст. Лучше держать всё предельно простым: один запрос с фильтрами, подсчётом и проекцией в DTO. Что вообще хотим от пагинации Когда фронт просит список пользователей, ему нужно не только «20 штук с offset», а нормальные данные • Текущая страница. • Размер страницы. • Список элементов. • Общее количество записей под этими фильтрами. Контейнер для любого списка: пользователей, заказов или логов.
public sealed record Paginated<T>(
    IReadOnlyList<T> Items,
    int Page,
    int Size,
    int Total
);
• Items то, что реально отображаем. • Page номер текущей страницы. • Size сколько элементов на странице. • Total сколько записей всего под заданным фильтром. Зачем DTO, а не сущность из EF • EF сущность часто содержит поля, которые нельзя светить наружу (пароли, внутренние флаги, технические поля). • DTO можно менять отдельно от внутренней модели база может жить своей жизнью, а API остаётся стабильным. • EF Core умеет проецировать прямо в DTO через Select, не тянуть все поля сущности и не включать трекинг. В итоге хендлер не выкидывает наружу сырые сущности, а отдаёт ровно то, что нужно клиенту. Как выглядит запрос сверху
public sealed record SearchUsersQuery(
    string? Q,
    int Page = 1,
    int Size = 20
) : IRequest<Paginated<UserSummary>>;
• Q — строка поиска. • Page — номер страницы. • Size — размер страницы. Контроллер ничего не знает о базе и EF он просто пробрасывает запрос в Application слой:
[HttpGet]
public async Task<ActionResult<Paginated<UserSummary>>> Search(
    [FromQuery] string? q,
    [FromQuery] int page,
    [FromQuery] int size,
    ISender sender,
    CancellationToken ct
)
{
    var result = await sender.Send(new SearchUsersQuery(q, page, size), ct);
    return Ok(result);
}
Что делает хендлер под капотом
public async Task<Paginated<UserSummary>> Handle(
        SearchUsersQuery query,
        CancellationToken ct)
    {
        var users = _db.Users.AsQueryable();

        if (!string.IsNullOrWhiteSpace(query.Q))
        {
            var q = query.Q.Trim();
            users = users.Where(u =>
                u.Email.Contains(q) ||
                u.Name.Contains(q));
        }

        var total = await users.CountAsync(ct);

        var items = await users
            .OrderBy(u => u.Email)
            .Skip((query.Page - 1) * query.Size)
            .Take(query.Size)
            .AsNoTracking()
            .Select(u => new UserSummary(
                u.Id,
                u.Email,
                u.IsActive
            ))
            .ToListAsync(ct);

        return new Paginated<UserSummary>(
            items,
            query.Page,
            query.Size,
            total
        );
    }
AsQueryable() чтобы можно было постепенно навешивать фильтры. • Фильтрация по Q делается в базе, а не в памяти. Email и Name фильтруются прямо в SQL. ​• CountAsync считает Total для уже отфильтрованного набора, без Skip/Take. Это количество строк, которые удовлетворяют фильтрам. • Skip и Take делают пагинацию на стороне БД через OFFSET / FETCH или аналог, а не в памяти приложения. • AsNoTracking() говорит EF Core не отслеживать сущности в change tracker, что ускоряет чистые запросы на чтение. • Select сразу проецирует в UserSummary EF не создаёт полноценные сущности, не подгружает лишние поля и не собирает сложные графы. Всё это превращается в один адекватный SQL запрос, а не в серию SELECT * плюс ручная фильтрация и подсчёты. Паттерн пагинации это не про сложность, а наоборот про простоту и предсказуемость. Отдельные DTO, контейнер Paginated<T>, один явный запрос с фильтрами, подсчётом и AsNoTracking() дают API, которое не врёт клиенту, хорошо масштабируется и остаётся читабельным через год. 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #sharp_view
Hammasini ko'rsatish...
👍 29 2
00:31
Video unavailableShow in Telegram
IDE-навигация для C# прямо в браузере Привычка к мощным инструментам вроде Visual Studio или Rider делает работу с «голым» текстом в веб-интерфейсе GitLab мучительной. Особенно когда в пулл-реквесте нужно провалиться в определение класса или найти все использования метода, чтобы убедиться, что рефакторинг ничего не сломал. На платформе SourceCraft для C# проектов реализована полноценная навигация по коду. Система строит семантический индекс, позволяя использовать Go to Definition и Find Usages непосредственно в окне просмотра пулл-реквеста. Это избавляет от необходимости стягивать ветку локально при проверке. Посмотрите, как это работает на практике → https://sourcecraft.dev/code-navigation-demo/uikit/pr/2040
Hammasini ko'rsatish...
C#_edited.mp417.89 MB
🥱 5👍 3🤩 2
🏆 Подборка топ-вакансий для шарпистов за неделю C#/.NET-разработчикот 200 000 ₽ и удалёнка. Senior .NET Engineer до 5 000 $ на гибрид в Минске. Senior .NET Software Engineer до 7 000 $ удалённо. С такими деньгами легко можно попасть в топ 3% разрабов по ЗП. Бустер — Удалённо (в любом городе мира). ➡️ Еще больше топовых вакансий — в нашем канале C# Jobs 🐸 Библиотека шарписта
Hammasini ko'rsatish...
👍 1
⚙️Паттерн пагинации и фильтрации через один запрос и нормальные DTO Пагинация в API часто превращается либо в магию репозиториев, либо в жуткий копипаст. Лучше держать всё предельно простым: один запрос с фильтрами, подсчётом и проекцией в DTO. Что вообще хотим от пагинации Когда фронт просит список пользователей, ему нужно не только «20 штук с offset», а нормальные данные • Текущая страница. • Размер страницы. • Список элементов. • Общее количество записей под этими фильтрами.
public sealed record Paginated<T>(
    IReadOnlyList<T> Items,
    int Page,
    int Size,
    int Total
);
Это контейнер для любого списка: пользователей, заказов или логов. Items то, что реально отображаем. Page номер текущей страницы. Size сколько элементов на странице. Total сколько записей всего под заданным фильтром. 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #sharp_view
Hammasini ko'rsatish...
🛠 Инструмент для трассировки без шума в коде В ASP.NET трассировка маршрутизации, middleware и хостинга держится не на конкретном логгере, а на связке DiagnosticSource и DiagnosticListener. Смысл DiagnosticListener в том что вы можете из кода публиковать диагностические события, не навязывая никому ни конкретный логгер, ни конкретный APM. Источник событий ничего не знает о подписчиках, а подписчики могут подключаться и отключаться динамически, не требуя изменений основной логики. Простой пример:
public static class OrderDiagnostics
{
    public static readonly DiagnosticListener Listener =
        new("MyApp.Orders");
}

public async Task ProcessOrder(Order order)
{
    if (OrderDiagnostics.Listener.IsEnabled("OrderProcessed"))
        OrderDiagnostics.Listener.Write("OrderProcessed", new { order.Id });

    // основная логика обработки
}
Если никто не подписан, проверка IsEnabled сразу вернет false и код почти ничего не стоит по времени. Как только появляется listener, он может наблюдать за событиями, строить трейс, метрики или слать данные в OpenTelemetry. 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #il_люминатор
Hammasini ko'rsatish...
🔥 6👍 4 3
Photo unavailableShow in Telegram
🎁 Письмо Деду Морозу До Нового Года 15 дней! Что бы вы хотели получить в подарок? Годовая премия не в счёт, это всегда как рулетка — повезёт/не повезёт. Админ хотел бы набор оперативной памяти, желательно гига 32, откладывал до последнего и вот итог.. 💬 Делитесь своими хотелками или сразу вишлистами в комментах 👇 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #entry_point
Hammasini ko'rsatish...
😁 8 1
Photo unavailableShow in Telegram
👨‍💻 Microsoft показали рабочий рецепт iOS виджетов В официальном .NET блоге появилась большая статья о том как собирать iOS виджеты поверх .NET MAUI не теряя нативности. Автор делится практическим опытом, который раньше приходилось выкапывать по кускам в доках Apple и чужих репозиториях. Статья не пошаговый туториал, а набор ключевых шагов и граблей от настроек App Groups и bundle id до интеграции Xcode виджет расширения в MAUI проект. ➡️ Читать статью 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #sharp_view
Hammasini ko'rsatish...
👍 8
GetElapsedTime вместо ручного Stopwatch шаблона Многие до сих пор измеряют время в .NET по старинке создают экземпляр Stopwatch, вызывают Start, ждут выполнение и читают Elapsed. Но есть более простой и аккуратный способ через Stopwatch.GetTimestamp и Stopwatch.GetElapsedTime. Классический шаблон выглядит так:
long start = Stopwatch.GetTimestamp();

// код, который нужно измерить
await ProcessOrderAsync();

TimeSpan elapsed = Stopwatch.GetElapsedTime(start);
GetElapsedTime вычисляет разницу между текущим timestamp и сохранённым значением и возвращает TimeSpan без создания экземпляра Stopwatch. В результате нет лишней аллокации. 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #sharp_view
Hammasini ko'rsatish...
👍 41 5🥰 4🔥 1
Photo unavailableShow in Telegram
🚦 SemaphoreSlim в проде — не просто «асинхронный lock» SemaphoreSlim часто кидают в код как самое простое решение и успокаиваются. В проде этого мало, ведь малейшая ошибка с Release, областью блокировки или per-key словарем легко превращается в дедлок, гонку или утечку памяти. Самый частый фейл — банальное «забыли Release». Исключение между WaitAsync и finally и семафор навсегда занят поэтому все будущие вызовы повисают. Помогает только жесткое правило всегда оборачивать WaitAsync в try finally и не вставлять лишний код между ними особенно никакой логики которая может бросить исключение. Вторая классика — блокировки внутри async кода. Варианты вроде _lock.Wait() или .Result внутри секции под SemaphoreSlim открывают прямую дорогу к дедлокам, потому что блокирующий вызов держит поток, а продолжение ждет этот же поток. Общий принцип не блокировать внутри асинхронной критической секции если нужно синхронное API выносить его в Task.Run до входа в lock. Поэтому в проде почти всегда лучше прятать SemaphoreSlim за абстракцией AsyncLock. Обертка с LockAsync() возвращающей IDisposable снимает часть рисков. 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #il_люминатор
Hammasini ko'rsatish...
12🥰 1
Photo unavailableShow in Telegram
Сборщик мусора для старых знаний В экосистеме .NET всё меняется, но фундамент вечен. Если чувствуешь, что уперся в потолок сеньорити, пора инвестировать в хард-скиллы, а не просто учить новый синтаксис C 12. Оффер 1 + 2: Покупаешь один курс (по старшей цене) — получаешь доступ к трем. Выбор .NET-комьюнити: — архитектуры и шаблоны проектирования (SOLID, GRASP и вот это всё); — алгоритмы и структуры данных. Скомпилировать успех Акция до 31 декабря. NullReferenceException при выборе? Пиши сюда: @manager_proglib
Hammasini ko'rsatish...
2🥰 1
Photo unavailableShow in Telegram
👨‍💻 Не хватает комментария «Создаёт переменную x равную 10» 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #garbage_collector
Hammasini ko'rsatish...
😁 48 1🥰 1🌚 1👾 1
⚙️ Один обработчик вместо сотни try catch Когда в проекте десятки эндпоинтов, разъезжающий по коду try catch быстро превращается в свалку. Гораздо проще один раз настроить глобальный маппинг исключений в HTTP статус и возвращать нормальные ProblemDetails для всех ошибок. ASP.NET уже умеет работать с ProblemDetails из коробки, нужно только включить службу и повесить обработчик ошибок. В примере вся логика перевода исключений в HTTP ответы живет в одном месте:
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler(appErr =>
{
    appErr.Run(async ctx =>
    {
        var ex = ctx.Features.Get<IExceptionHandlerFeature>()?.Error;

        var (status, title) = ex switch
        {
            ConcurrencyException => (StatusCodes.Status409Conflict, "Concurrency conflict"),
            NotFoundException    => (StatusCodes.Status404NotFound, "Resource not found"),
            _                    => (StatusCodes.Status500InternalServerError, "Server error")
        };

        ctx.Response.StatusCode = status;

        await ctx.Response.WriteAsJsonAsync(new ProblemDetails
        {
            Status   = status,
            Title    = title,
            Detail   = app.Environment.IsDevelopment() ? ex?.Message : null,
            Instance = ctx.Request.Path
        });
    });
});
Любые новые исключения добавляются через одну запись в switch, без походов по контроллерам, а все ответы об ошибках приходят в едином формате application/problem+json, что упрощает жизнь фронту и интеграциям. 📍 Навигация: ВакансииЗадачиСобесы 🐸Библиотека шарписта #sharp_view
Hammasini ko'rsatish...
22👍 18