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

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

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

Все самое полезное для C#-разработчика в одном канале. Наши курсы: https://clc.to/y3LDtw По рекламе: @proglib_adv Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead

نمایش بیشتر

📈 تحلیل کانال تلگرام Библиотека шарписта | C#, F#, .NET, ASP.NET

کانال Библиотека шарписта | C#, F#, .NET, ASP.NET (@csharpproglib) در بخش زبانی روسی بازیگری فعال است. در حال حاضر جامعه شامل 21 707 مشترک است و جایگاه 5 962 را در دسته فناوری و برنامه‌ها و رتبه 30 301 را در منطقه روسيا دارد.

📊 شاخص‌های مخاطب و پویایی

از زمان ایجاد در невідомо، پروژه رشد سریعی داشته و 21 707 مشترک جذب کرده است.

بر اساس آخرین داده‌ها در تاریخ 27 اوت, 2026، کانال فعالیت پایداری دارد. در ۳۰ روز گذشته تغییر اعضا برابر -42 و در ۲۴ ساعت گذشته برابر 3 بوده و همچنان دسترسی گسترده‌ای حفظ شده است.

  • وضعیت تأیید: تأیید نشده
  • نرخ تعامل (ER): میانگین تعامل مخاطب 15.91% است و در ۲۴ ساعت نخست پس از انتشار، محتوا معمولاً 7.92% واکنش نسبت به کل مشترکان کسب می‌کند.
  • دسترسی پست‌ها: هر پست به طور میانگین 3 454 بازدید دریافت می‌کند. در اولین روز معمولاً 1 718 بازدید جمع‌آوری می‌شود.
  • واکنش‌ها و تعامل: مخاطبان به‌طور فعال حمایت می‌کنند؛ میانگین واکنش به هر پست 26 است.
  • علایق موضوعی: محتوا بر موضوعات کلیدی مانند .net, шарписта, навигация, await, string تمرکز دارد.

📝 توضیح و سیاست محتوایی

نویسنده این فضا را محل بیان دیدگاه‌های شخصی توصیف می‌کند:
Все самое полезное для C#-разработчика в одном канале. Наши курсы: https://clc.to/y3LDtw По рекламе: @proglib_adv Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead

به لطف به‌روزرسانی‌های پرتکرار (آخرین داده در تاریخ 28 اوت, 2026)، کانال همواره به‌روز و دارای دسترسی بالاست. تحلیل‌ها نشان می‌دهد مخاطبان به‌طور فعال با محتوا تعامل دارند و آن را به نقطه اثرگذاری مهم در دسته فناوری و برنامه‌ها تبدیل کرده‌اند.

21 707
مشترکین
+324 ساعت
-137 روز
-4230 روز
آرشیو پست ها
📝 Вытащить текст из 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

👍 На курсе по контролируемой разработке AI-агентов мы будем разбирать ровно то, о чём говорит Владислав в голосовом, но уже в формате системной практики. 📅 Старт курса — 20 апреля. Если хотите разобраться, как строить управляемые агентные системы: ➡️ Присоединяйтесь. P.S. С первого занятия будет практика: код и разбор реальных ошибок, а не только теория.

پیام ویدیو01:00

👨‍💻 NuGet стал удобнее Разработчик запустил nugetz.dev — альтернативный интерфейс для поиска по реестру NuGet. Стандартный
👨‍💻 NuGet стал удобнее Разработчик запустил nugetz.dev — альтернативный интерфейс для поиска по реестру NuGet. Стандартный поиск на nuget.org работает, но медленно и неудобно. Когда выбираешь библиотеку, хочешь быстро понять: пакет живой, как давно обновлялся, насколько популярен. Сейчас это занимает лишнее время. Nugetz решает именно это. Тот же реестр, но с чистым интерфейсом, быстрой выдачей и без лишнего шума на экране. Без регистрации и рекламы. Идея пришла от npmx — похожего инструмента для npm-экосистемы. Rodrigo просто спросил себя, почему у .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# backend-разработчик в команду Security — Офис/гибрид в Москве Backend Engineer — от 175 000 до 325 000 ₽, удалёнка C#/.NET разработчик — от 350 000 ₽, удалёнка Бустер — Удалённо в любом городе мира. ➡️ Еще больше топовых вакансий — в нашем канале C# Jobs 🐸 Библиотека шарписта

🛠 Жизни зависимостей в 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

🗓 Merge conflict, но для календаря В git есть автоматический резолв конфликтов. Теперь такое есть и для встреч — Microsoft C
🗓 Merge conflict, но для календаря В git есть автоматический резолв конфликтов. Теперь такое есть и для встреч — Microsoft Copilot в Outlook и Teams умеет сам переносить встречи, если в расписании возник конфликт. Работает для личных встреч и 1:1. Групповые звонки, встречи длиннее 5 часов и повторяющиеся реже раза в месяц — пока не поддерживаются. Но для большинства рабочих 1:1 — уже удобно. ➡️ Источник 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #async_news

🔌 Пишите интерфейс так, чтобы не объяснять Хороший код легко использовать правильно — и сложно использовать неправильно. Это
🔌 Пишите интерфейс так, чтобы не объяснять Хороший код легко использовать правильно — и сложно использовать неправильно. Это важно при проектировании API: даже внутреннего. На ревью кода интерфейсов проверяют логику, покрытие тестами, производительность. Но неудобный интерфейс это технический долг, который будет копиться каждый раз, когда кто-то будет использовать этот код. Вот на что стоит обращать внимание: • Понятен ли смысл метода. Название должно говорить само за себя без комментария над функцией и без погружения в реализацию. Если приходится читать тело метода, чтобы понять что он делает, значит имя плохое. • Предсказуемо ли поведение. Метод с одинаковыми параметрами должен возвращать одинаковый результат. Скрытые побочные эффекты и неочевидные состояния — прямой путь к багам, которые воспроизводятся через раз. • Булевые флаги это тревожный знак. Два булевых параметра подряд — почти всегда признак того, что функция делает слишком много или интерфейс не доработан:
ProcessData(bool flag1, bool flag2);
Явные типы — намерение читается сразу:
ProcessData(ProcessMode mode, ValidationOptions options);
Исключения или типы результата. Исключения созданы для исключительных ситуаций, а типы результата для ожидаемых ошибок. Смешивать их = заставлять пользователя угадывать, что пойдёт не так и в каком виде. • Минимум обязательных параметров. Чем больше параметров нужно передать для базового вызова, тем выше порог входа. Если для простого случая нужно заполнить пять аргументов, скорее всего интерфейс нуждается в умных значениях по умолчанию или отдельном упрощённом методе. Удобный интерфейс это уважение к тем, кто будет с ним работать. И к себе через полгода, когда придётся вернуться к этому коду. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #il_люминатор

🤔 Спам тимлидам, фейковые офферы и приукрашенное резюме IT-рынок 2026 года — это не конкурс честных и талантливых. Компании
🤔 Спам тимлидам, фейковые офферы и приукрашенное резюме IT-рынок 2026 года — это не конкурс честных и талантливых. Компании говорят об экологичной культуре, а сами гостят после четырёх этапов отбора. На одну вакансию — тысяча откликов за сутки. В таких условиях выигрывают не самые опытные, а самые адаптивные. ➡️ Узнать приёмы тех, кто смог 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view

👨‍💻 Генерируйте 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

💻 Утечки памяти в .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_люминатор

🔄 Cake 6.0.0 вышел Cake — это инструмент автоматизации сборки для .NET-проектов. Скрипты пишутся на C# с простым DSL, которы
🔄 Cake 6.0.0 вышел Cake — это инструмент автоматизации сборки для .NET-проектов. Скрипты пишутся на C# с простым DSL, который покрывает компиляцию, тестирование, публикацию и всё, что обычно делают в CI/CD пайплайне. Логирование теперь принимает интерполированные строки напрямую. Сообщение формируется только если текущий уровень логирования активен:
Information($"Building {project} v{version}");

Verbose(log => log($"Processing {items.Count} items in {stopwatch.ElapsedMilliseconds} ms"));
Cake.Sdk получил поддержку in-process NuGet клиента. Теперь через #tool и InstallTool можно устанавливать любые NuGet пакеты прямо в инструменты. Добавлена поддержка .slnx файлов. DotNetTest и парсинг решений теперь распознают XML-формат solution файлов, а автоопределение типа пути включает .slnx. Из других изменений: NuGetPack теперь поддерживает поле ReadMe для readme пакета, в AssemblyInfo creator можно добавлять несколько экземпляров одного атрибута, in-process NuGet restore заработал с аутентификацией через приватные фиды. Есть breaking change для GitLab CI — поля CI_PIPELINE_ID и CI_BUILD_ID сменили тип с int на long, так как на gitlab.com идентификаторы давно вышли за пределы 32 бит. ➡️ Release Notes 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #async_news

📝 Логирование со строковой интерполяцией Логирование c интерполяцией строк один из самых распространённых источников лишних аллокаций в .NET-приложениях. Особенность в том, что код выглядит абсолютно нормально и работает правильно — просто дорого. Что происходит с интерполяцией:
logger.LogInformation($"User {userId} logged in at {time}");
Компилятор разворачивает это примерно в:
logger.LogInformation(string.Format("User {0} logged in at {1}", userId, time));
Строка формируется до вызова метода. Если уровень логирования Information отключён, строка всё равно создаётся, занимает память и тут же выбрасывается сборщиком мусора. Структурное логирование решает проблему:
logger.LogInformation("User {UserId} logged in at {Time}", userId, time);
Здесь строка — это шаблон. Аргументы передаются отдельно. Логгер сначала проверяет, активен ли уровень, и только потом форматирует сообщение. Если уровень выключен — аллокации нет вообще. Бонус: структурное логирование позволяет индексировать поля в системах вроде Seq, Elasticsearch, Datadog — вы сможете искать по UserId как по полю, а не парсить текст. Начиная с .NET 6 есть ещё лучший вариант через compile-time source generators:
// Генерирует оптимальный код на этапе компиляции:
[LoggerMessage(Level = LogLevel.Information, Message = "User {UserId} logged in at {Time}")]
partial void LogUserLogin(int userId, DateTime time);
Никаких аллокаций, никакого боксинга, максимальная производительность — и всё это без изменения читаемости кода. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #il_люминатор

Энтерпрайз убивает драйв? Стань техническим кофаундером в EdTech-стартапе 🚀 Proglib App — платформа для обучения разработчиков (курсы, квизы, ИИ-агенты). MVP уже в проде, пользователи растут. Проекту нужен сильный инженер, готовый взять на себя роль технического лидера и строить продукт вместе с основателем. Это вызов для тех, кто перерос роль «просто разработчика» и хочет влиять на архитектуру и бизнес-логику напрямую. 🛠️ Стек (современный Fullstack): TypeScript, React 18, Express 5, PostgreSQL, Drizzle ORM. Почему это может быть интересно:Никакой бюрократии: только код, продукт и архитектурные решения. • Инструменты: работа с ИИ-ассистентами (Claude Code, Cursor). • Рост: путь от MVP до масштабного сервиса в роли партнёра. Ожидания: • Крепкий бэкграунд в разработке и понимание архитектуры БД. • Готовность работать с TS/React/Node.js. • Автономность и продуктовое мышление. Удалёнка, гибкий график, полная свобода в реализации идей. Готов сменить привычный стек на роль кофаундера? Пиши о себе и кидай GitHub 👇 @proglibrary_feedback_bot

🌍 Сравнение строк и культура Когда вы сравниваете строки в C#, результат зависит не только от содержимого, но и от того, как вы сравниваете. И здесь кроется целый класс багов, которые воспроизводятся только на машинах с определёнными региональными настройками. Два режима сравнения: Ordinal — побайтовое сравнение Unicode-значений. Быстрое, предсказуемое, не зависит от культуры. CurrentCulture — сравнение по правилам текущей локали операционной системы. Медленнее, результат может отличаться на разных машинах. Пример с немецким языком:
string a = "straße";  // немецкое "улица"
string b = "strasse"; // то же слово, другое написание

a.Equals(b, StringComparison.CurrentCultureIgnoreCase); // true на de-DE
a.Equals(b, StringComparison.CurrentCultureIgnoreCase); // false на en-US
a.Equals(b, StringComparison.OrdinalIgnoreCase);        // false везде
Один и тот же код даёт разные результаты в зависимости от того, где запущен. На машине разработчика работает, на продакшен-сервере — нет. Турецкая проблема:
// В турецкой локали (tr-TR):
"I".ToLower() == "ı"  // не "i", а "ı" (без точки)
"i".ToUpper() == "İ"  // не "I", а "İ" (с точкой)

// Поэтому:
string input = "FILE";
input.ToLower() == "file" // false на турецкой машине!
Именно из-за этого Microsoft SQL Server годами имел баги в коде, который работал везде, кроме турецких инсталляций. Анализатор CA1307 в .NET предупреждает о вызовах сравнения без явного указания StringComparison. Включите его — он поймает большинство таких мест автоматически. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #il_люминатор

👨‍💻 string в C# — не просто текст string — это ссылочный тип с особой поддержкой рантайма. Внутри он хранит непрерывный бло
👨‍💻 string в C# — не просто текст string — это ссылочный тип с особой поддержкой рантайма. Внутри он хранит непрерывный блок UTF-16 кодовых единиц. Отсюда первый сюрприз:
string s = "😊";
Console.WriteLine(s.Length); // 2, не 1
Length считает не символы, а UTF-16 кодовые единицы. Эмодзи и многие Unicode-символы занимают две единицы — суррогатную пару. 📍 Навигация: ВакансииЗадачиСобесы 🐸 Библиотека шарписта #sharp_view