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

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

رفتن به کانال در Telegram

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

نمایش بیشتر
2025 سال در اعدادsnowflakes fon
card fon
22 350
مشترکین
-624 ساعت
-327 روز
-14630 روز
آرشیو پست ها
👨‍💻 Worker Services и Channels вместо сторонних библиотек Каждый разработчик сталкивался с необходимостью выполнять долгие операции в фоне: отправка писем, обработка платежей, генерация отчётов, синхронизация данных. Обычно первая мысль — взять Hangfire, Quartz или Azure Functions. Но .NET 9 предоставляет встроенные примитивы, которые отлично справляются с этой задачей самостоятельно. Традиционные подходы — блокирующая коллекция и самописные очереди имеют недостатки: требуют ручной синхронизации, рискуют блокировкой потоков, не имеют встроенной поддержки обратного давления. Реализуем очередь задач с помощью каналов и фоновые сервисы Интерфейс и реализация очереди:
public interface IBackgroundTaskQueue
{
    ValueTask QueueAsync(Func<CancellationToken, Task> workItem);
    ValueTask<Func<CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken);
}

public class BackgroundTaskQueue : IBackgroundTaskQueue
{
    private readonly Channel<Func<CancellationToken, Task>> _queue;

    public BackgroundTaskQueue(int capacity = 100)
    {
        var options = new BoundedChannelOptions(capacity)
        {
            SingleReader = false,
            SingleWriter = false,
            FullMode = BoundedChannelFullMode.Wait
        };
        _queue = Channel.CreateBounded<Func<CancellationToken, Task>>(options);
    }

    public async ValueTask QueueAsync(Func<CancellationToken, Task> workItem)
        => await _queue.Writer.WriteAsync(workItem);

    public async ValueTask<Func<CancellationToken, Task>> DequeueAsync(CancellationToken cancellationToken)
        => await _queue.Reader.ReadAsync(cancellationToken);
}
Фоновые сервисы для обработки:
public class BackgroundWorker : BackgroundService
{
    private readonly IBackgroundTaskQueue _taskQueue;
    private readonly ILogger<BackgroundWorker> _logger;

    public BackgroundWorker(IBackgroundTaskQueue taskQueue, ILogger<BackgroundWorker> logger)
    {
        _taskQueue = taskQueue;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Фоновый worker запущен");
        
        while (!stoppingToken.IsCancellationRequested)
        {
            var workItem = await _taskQueue.DequeueAsync(stoppingToken);
            try
            {
                await workItem(stoppingToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Ошибка при выполнении задачи");
            }
        }
        
        _logger.LogInformation("Worker останавливается...");
    }
}
Использование в контроллере:
app.MapPost("/send-email", async (IBackgroundTaskQueue queue) =>
{
    await queue.QueueAsync(async token =>
    {
        await Task.Delay(1000, token); // имитация отправки
        Console.WriteLine($"Email отправлен в {DateTime.UtcNow}");
    });
    return Results.Accepted();
});
Запрос возвращается немедленно, а работа продолжается в фоне. Queue автоматически буферизирует задачи, управляет нагрузкой и применяет обратное давление, если очередь переполнится. Когда использовать этот подход Подходит: • Внутренняя обработка задач в приложении • Нет нужды в UI-панели мониторинга • Self-contained сервисы Возьмите библиотеку, если: • Нужна распределённая обработка • Требуется веб-интерфейс для управления • Задачи должны пережить перезагрузку приложения ➡️ Источник 🐸 Библиотека шарписта #sharp_view
نمایش همه...
👍 17
Photo unavailableShow in Telegram
نمایش همه...
😁 14🥱 12🌚 1
❓ Какой пост особенно зашел за эту неделюAnonymous voting
  • Как торговаться о зарплате
  • Мемы
  • Задачка с собеса
  • Ленивый фильтры
  • Два поста про дедлоки
  • Звуки флоппи дисководов
0 votes
🤔 2
Photo unavailableShow in Telegram
📰 Шестидневные новости Вспомним, что произошло за 6 рабочих дней. — C# сохраняет популярность Вышел ежегодный Octoverse от GitHub, в котором отмечается рекордный рост числа разработчиков, активность в проектах с AI и смена лидерства по языкам программирования. — Unity Lite. Простой старт в 3D для всех Инструмент от Unity для создания интерактивных 3D-сцен без программирования, с удобной навигацией и редактором внутри браузера/. — Нейросети поиграли в покер Победителем стала модель OpenAI o3 с выигрышем в $36,691 виртуальных денег. Второе место занял Claude Sonnet 4.5, а третье — Grok 4 — Новые кастомные агенты Copilot для .NET GitHub запускает интеллектуальных помощников для оптимизации рабочего процесса .NET‑разработчиков. — Звуки флоппи-дисководов в эмуляторе 🐸 Библиотека шарписта #async_news
نمایش همه...
Photo unavailableShow in Telegram
☺️ 6 дней труда — пора отдыхать Шестидневная рабочая неделя подошла к концу, и наконец-то время расслабиться. Используйте свободное время для восстановления и новых впечатлений. 💬 А вы как планируете провести ближайшие дни? Уже отдыхаете или еще у дел? Ждем ваши ответы в комментариях 👇 🐸 Библиотека шарписта #entry_point
نمایش همه...
💯 9😁 1
Photo unavailableShow in Telegram
💲 Как договориться о зарплате: 9 стратегий В зарплатных переговорах нет универсального сценария. Но есть проверенные стратегии под разные ситуации. В статье 9 тактик от открытой до «я никуда не тороплюсь» — с готовыми фразами для собеседования. ➡️ Выбирайте свою в зависимости от опыта, позиции и типа компании 🐸 Библиотека шарписта
نمایش همه...
👍 5
Photo unavailableShow in Telegram
نمایش همه...
😁 37👍 1🤔 1
✏️ Как найти два повторяющихся числа в массиве Вам дан массив nums длиной n+2, содержащий числа от 0 до n-1. Два числа случайным образом появились в списке дважды. Нужно вернуть эти два числа. Например, для входа [0][1][1][2][3][3][4] ответ будет [1][3]. Для решения можно воспользоваться подсчётом количества появлений каждого числа. Если встретили число во второй раз — записываем его в ответ:
public int[] GetSneakyNumbers(int[] nums)
{
    int n = nums.Length;
    int[] count = new int[101];
    int[] res = new int[2];
    int idx = 0;

    foreach (var num in nums)
    {
        count[num]++;
        if (count[num] == 2)
        {
            res[idx] = num;
            idx++;
        }
    }
    return res;
}
При помощи вспомогательного массива считаем, сколько раз встречается каждое число, и когда оно появилось второй раз — запоминаем. ➡️ Попробовать решить 🐸 Библиотека шарписта #dotnet_challenge
نمایش همه...
8🥱 4😁 1
Photo unavailableShow in Telegram
🎃 Хэллоуин и код Сегодня день, когда можно немного отвлечься от кода и рутины. Костюм помогает прочувствовать праздник, даже если это всего один день. 💬 Делитесь, кто в костюме сегодня, оставляйте свои истории 👇 🐸 Библиотека шарписта #entry_point
نمایش همه...
Photo unavailableShow in Telegram
🎃 Хэллоуин в Proglib Academy: скидки, призы и... немного паники Сегодня 31 октября, и это не просто время тыкв и призраков, это ПОСЛЕДНИЙ ДЕНЬ, когда ты можешь выиграть макбук! → Купи любой курс со скидкой 40% 💸 → Начни обучение, чтобы пройти 2 недели к 15 ноября 🎓 → Напиши куратору #розыгрыш ✍️ Всё! Теперь ты в игре. 👉 Сейчас или никогда!
نمایش همه...
👨‍💻 Ленивый фильтр больших файлов Когда файл огромный, главное — не тянуть всё в память. Пример:
var errors = File.ReadLines(logPath).Where(l => l.Contains("ERROR"));
ReadLines читает файл построчно, не загружая всё сразу. Не добавляйте .ToList(), если хочется сохранить ленивость — иначе всё материализуется в памяти. 🐸 Библиотека шарписта #sharp_view
نمایش همه...
🔥 14 1
⭐️ Подборка вакансий для шарпистов .NET-разработчик на удалёнку. Backend-developer в Москве от 200 000 ₽. .NET Developer от 200 000 ₽ с удалёнкой. Бустер — Удалённо (в любом городе мира). ➡️ Еще больше топовых вакансий — в нашем канале C# Jobs
نمایش همه...
2👍 2🥱 1
⚡️ Deadlock в EF Core: как восстановиться Даже самая оптимизированная система не застрахована от deadlock на 100%. При высоких нагрузках, пиковых моментах или редких edge-case сценариях они всё равно могут возникнуть. Важно не предотвращение на 100% (это невозможно), а грамотное восстановление. • Умный ретрай с экспоненциальной задержкой Простой повтор без задержки только усугубит ситуацию. Используйте экспоненциальную задержку:
public async Task<bool> SaveWithRetryAsync(DbContext context, int maxRetries = 3)
{
    for (int attempt = 0; attempt < maxRetries; attempt++)
    {
        try
        {
            await context.SaveChangesAsync();
            return true;
        }
        catch (DbUpdateException ex) when (IsDeadlock(ex))
        {
            if (attempt == maxRetries - 1)
                throw;
                
            // Экспоненциальная задержка: 100ms, 200ms, 400ms
            var delay = TimeSpan.FromMilliseconds(100 * Math.Pow(2, attempt));
            await Task.Delay(delay);
            
            Console.WriteLine($"Deadlock detected, retry {attempt + 1}/{maxRetries}");
        }
    }
    
    return false;
}

bool IsDeadlock(Exception ex) =>
    ex.InnerException is SqlException sqlEx && 
    (sqlEx.Number == 1205 || // Deadlock victim
     ex.InnerException.Message.Contains("deadlocked"));
• Ограничение параллелизма Если ваше приложение обрабатывает большие пакеты данных, ограничьте количество одновременных операций:
public class OrderProcessor
{
    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(5); // Макс 5 одновременно
    
    public async Task ProcessOrdersAsync(List<int> orderIds)
    {
        var tasks = orderIds.Select(id => ProcessWithSemaphoreAsync(id));
        await Task.WhenAll(tasks);
    }
    
    private async Task ProcessWithSemaphoreAsync(int orderId)
    {
        await _semaphore.WaitAsync();
        try
        {
            await using var context = new AppDbContext();
            var order = await context.Orders.FindAsync(orderId);
            order.Status = "Processed";
            await SaveWithRetryAsync(context);
        }
        finally
        {
            _semaphore.Release();
        }
    }
}
• Логирование и анализ Недостаточно просто повторить — нужно понять причину:
catch (DbUpdateException ex) when (IsDeadlock(ex))
{
    _logger.LogWarning(ex, 
        "Deadlock on order {OrderId}, attempt {Attempt}/{MaxAttempts}", 
        orderId, attempt + 1, maxRetries);
    
    // Отправьте метрику в мониторинг
    _telemetry.TrackMetric("Deadlocks", 1, new Dictionary<string, string>
    {
        ["Entity"] = "Order",
        ["Operation"] = "Update"
    });
}
• Захват графов блокировок SQL Server создаёт подробные графы взаимоблокировок. Настройте их захват:
-- Extended Events для захвата deadlock
CREATE EVENT SESSION [DeadlockMonitoring] ON SERVER
ADD EVENT sqlserver.xml_deadlock_report
ADD TARGET package0.event_file(SET filename = N'C:\Logs\Deadlocks.xel')
WITH (MAX_MEMORY = 4096 KB, EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS);

ALTER EVENT SESSION [DeadlockMonitoring] ON SERVER STATE = START;
Сочетание правильного предотвращения и надежного восстановления создаст устойчивую систему, способную справиться с любыми нагрузками. Чтобы строить надёжные решения нужно знать архитектуру и уметь её спроектировать. Для этого можно пройти наш интенсив по архитектуре и шаблонам проектирования. Осталось всего 3 дня скидок! 🐸 Библиотека шарписта #sharp_view
نمایش همه...
17👍 5🔥 4
Photo unavailableShow in Telegram
14 вопросов, после которых вам не перезвонят Разбираем 14 вопросов, которые лучше не задавать на собеседовании: что не так с каждым из них и как переформулировать, чтобы получить нужную информацию без риска для репутации. ➡️ Прочитать статью 🐸 Библиотека шарписта
نمایش همه...
🥱 8👍 5😁 3
Photo unavailableShow in Telegram
Повышение надёжности .NET-приложений: как обрабатывать сбои и предотвращать каскадные ошибки. Даже самые стабильные системы ломаются — вопрос лишь в том, насколько вы готовы к этому. Библиотека Polly позволяет гибко управлять сбоями и повышать устойчивость микросервисов и API. На открытом вебинаре курса OTUS C# ASP.NET Core разработчик Виктор Дзицкий покажет, как использовать Polly и HttpClientFactory для защиты приложений от временных отказов и непредсказуемых сетевых ошибок. 📌 6 ноября, 20:00 Повышение надежности .NET-приложений с Polly — ключевые стратегии и политики Polly — настройка и комбинирование стратегий для сложных сценариев — защита от каскадных сбоев и готовые паттерны устойчивости — улучшения в .NET 8 Вебинар бесплатный и подойдёт .NET-разработчикам, работающим с микросервисами и внешними API, которые хотят сделать свои системы по-настоящему отказоустойчивыми. 👉 Регистрируйтесь: https://clc.to/zyj9ow Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
نمایش همه...
1
Photo unavailableShow in Telegram
C#-навигация прямо в браузере? Да, теперь и такое есть! 👀 Для тех, кто работает с C#, приятные новости от SourceCraft. Платформа добавила умную навигацию, которая понимает связи между функциями и позволяет переходить по объявлениям прямо в веб-интерфейсе — как в вашей любимой IDE. 🔥 А ИИ-ассистент теперь дописывает методы на C# не изолированно, а в контексте всего проекта. Для команд с разнесёнными код-ревью или для быстрого онбординга новичков — просто находка. Можно даже коммитить правки из браузера, не теряя типизацию.
نمایش همه...
🤔 7👍 3
⚡️ Deadlock в EF Core: как предотвратить Дедлоки редко проявляются в ходе разработки, но часто всплывают под реальной нагрузкой в продакшне. Дедлок — ситуация, когда две или более сессии базы данных блокируют друг друга, ожидая освобождения ресурсов. В итоге SQL Server прерывает одну из транзакций:
SqlException: Transaction (Process ID xx) was deadlocked on resources...
Пример простого дедлока: два контекста одновременно меняют одну строку и пытаются сохранить изменения. Один запрос блокирует строку, второй вызывает дедлок.
await using var context1 = new AppDbContext();
await using var context2 = new AppDbContext();

var order1 = await context1.Orders.FindAsync(1);
var order2 = await context2.Orders.FindAsync(1);

order1.Status = "Paid";
order2.Status = "Shipped";

await context1.SaveChangesAsync(); // Блокирует строку
await context2.SaveChangesAsync(); // Возможен deadlock
Стратегии предотвращения • Короткие транзакции Минимизируйте работу внутри транзакции:
await using var tx = await context.Database.BeginTransactionAsync();
var order = await context.Orders.FindAsync(orderId);
order.Status = "Paid";
await context.SaveChangesAsync();
await tx.CommitAsync();
Избегайте сетевых вызовов и посторонних запросов перед коммитом. • Правильные индексы Отсутствие индексов приводит к сканированию таблиц и длительным блокировкам. Используйте SQL Profiler для мониторинга. • Оптимальный уровень изоляции ReadCommitted обычно достаточен для большинства операций:
await using var tx = await context.Database.BeginTransactionAsync(
    IsolationLevel.ReadCommitted);
• Логика повторов Используйте встроенную политику retry в EF Core:
services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(connectionString, sql =>
        sql.EnableRetryOnFailure(
            maxRetryCount: 3,
            maxRetryDelay: TimeSpan.FromSeconds(5),
            errorNumbersToAdd: null)));
• RowVersion для контроля конкурентности
public class Order
{
    public int Id { get; set; }
    public string Status { get; set; }
    
    [Timestamp]
    public byte[] RowVersion { get; set; }
}
EF Core выбросит DbUpdateConcurrencyException при конфликте изменений. Дедлоки не баги, а следствие паттернов конкурентного доступа. 🐸 Библиотека шарписта #sharp_view
نمایش همه...
9👍 6
Photo unavailableShow in Telegram
🎁 Конкурс от Proglib Academy! Кстати, если кто-то ещё не в курсе — у нас тут раздают MacBook Pro 14. Да-да, не шутка, настоящий, железный, с M3 Pro Но! Чтобы успеть пройти 2 недели обучения к 15 ноября, курс нужно взять до конца октября — и сейчас на всё скидка 40%. Чтобы поучаствовать, нужно: 1️⃣ Покупаешь любой курс до конца октября; 2️⃣ Проходишь 2 недели обучения к 15 ноября; 3️⃣ Написать куратору в чат #розыгрыш. До 15 ноября, потом всё — поезд (и макбук) уйдёт. 👉 Участвовать в розыгрыше
نمایش همه...
3
Photo unavailableShow in Telegram
نمایش همه...
😁 30👍 2👏 1
🤩 Как взять последние символы строки в C# Когда работаешь с идентификаторами, хешами или логами, часто нужно быстро достать последние символы из строки. Для получения последних 10 символов используется оператор диапазона:
var last10 = text[^10..];
Такой способ делает код короче и легче для чтения. Но есть один момент — если строка короче десяти символов, программа выбросит ошибку. Чтобы этого избежать, добавьте проверку:
var last10 = text.Length >= 10 ? text[^10..] : text;
Теперь код работает безопасно даже с короткими строками. 🐸 Библиотека шарписта #sharp_view
نمایش همه...
14🥱 3🌚 2👾 2