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

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

@csharpproglib

Все самое полезное для C#-разработчика в одном канале.

Наши курсы: https://clc.to/y3LDtw

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

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

РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
Subscribers
21.7K
Photos
2.9K
Videos
46
Links
5.4K

Showing posts older than #6594 · Back to latest

Older Posts 20 shown
Post #6593 3.48K
😁 Он вам не веб-сервис

Вы замечали, что Windows работает не так, как раньше? Это всё из-за новомодных ИИ и веб-элементов. Первое пишет, а второе лагает.

Наткнулись на видео, где всё это выпиливают из актуальной Windows 11. Результат вас не порадует, но зато вы узнаете на что конкретно жаловаться в Microsoft.

➡️ Смотреть видео

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

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

#sharp_view
  • ❤ 4
  • 👍 3
  • 🥰 1
Post #6592 3.42K
💻 Свежий контент для Copilot

Проблема с Copilot: он не знает о новых штуках вроде Agent Framework. Решение от Microsoft: MCP сервер дает доступ к свежей .NET-документации прямо в инструментах разработки.

Сервер передает Copilot актуальные данные: гайды, код, уроки. Идеально для .NET 10, Aspire или оптимизации старых приложений. Контекст адаптируется под код.

➡️ Как всё это настроить

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

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

#sharp_view
  • 👍 3
Post #6591 3.44K
🔍 Подборка ИИ-инструментов для поиска работы за рубежом

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

Вместо того чтобы пытаться вручную тянуть LinkedIn, job‑борды и подготовку к интервью, имеет смысл собрать для себя связку из нескольких AI сервисов и переложить на них максимум рутины.

➡️ Список сервисов

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

🐸Библиотека шарписта
  • ❤ 2
  • 🥱 2
Post #6590 3.57K
💲 Дорогое логирование только в dev

Иногда нужно навесить на код тяжёлую отладочную диагностику, но в проде за неё платить не хочется. Для таких случаев есть атрибут Conditional, который полностью выкидывает вызовы метода из Release сборки.

Базовый пример:
[Conditional("DEBUG")]
public static void Trace(string message)
{
Console.WriteLine("[TRACE] " + message);
}


Это удобно для временного трассинга, сложных проверок и дорогих assert’ов, которые нужны только при разработке. Debug.Assert и Debug.WriteLine работают так же — они помечены [Conditional("DEBUG")], поэтому автоматически исчезают из релизной сборки.

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

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

#il_люминатор
  • 💯 8
  • ❤ 4
  • 🥱 1
Post #6589 3.46K
⚙️Паттерн пагинации и фильтрации через один запрос и нормальные 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
  • 👍 30
  • ❤ 5
Post #6587 3.56K
🏆 Подборка топ-вакансий для шарпистов за неделю

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

Senior .NET Engineer — до 5 000 $ на гибрид в Минске.

Senior .NET Software Engineer — до 7 000 $ удалённо. С такими деньгами легко можно попасть в топ 3% разрабов по ЗП.

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

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

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

🐸 Библиотека шарписта
  • 👍 1
Post #6585 3.67K
🛠 Инструмент для трассировки без шума в коде

В 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_люминатор
  • 🔥 7
  • 👍 4
  • ❤ 3
Post #6584 3.83K
🎁 Письмо Деду Морозу

До Нового Года 15 дней! Что бы вы хотели получить в подарок? Годовая премия не в счёт, это всегда как рулетка — повезёт/не повезёт.

Админ хотел бы набор оперативной памяти, желательно гига 32, откладывал до последнего и вот итог..

💬 Делитесь своими хотелками или сразу вишлистами в комментах 👇

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

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

#entry_point
  • 😁 8
  • ❤ 1
Post #6583 4.23K
👨‍💻 Microsoft показали рабочий рецепт iOS виджетов

В официальном .NET блоге появилась большая статья о том, как собирать iOS виджеты поверх .NET MAUI не теряя нативности.

Автор делится практическим опытом, который раньше приходилось выкапывать по кускам в доках Apple и чужих репозиториях.

Статья не пошаговый туториал, а набор ключевых шагов и граблей от настроек App Groups и bundle id до интеграции Xcode виджет расширения в MAUI проект.

➡️ Читать статью

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

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

#sharp_view
  • 👍 8
Post #6582 4.44K
⏳ 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
  • 👍 44
  • ❤ 7
  • 🥰 4
  • 🔥 1
Post #6581 4.09K
🚦 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_люминатор
  • ❤ 12
  • 🥰 1
Post #6580 3.81K
Сборщик мусора для старых знаний

В экосистеме .NET всё меняется, но фундамент вечен. Если чувствуешь, что уперся в потолок сеньорити, пора инвестировать в хард-скиллы, а не просто учить новый синтаксис C
12.

Оффер 1 + 2:

Покупаешь один курс (по старшей цене) — получаешь доступ к трем.

Выбор .NET-комьюнити:

— архитектуры и шаблоны проектирования (SOLID, GRASP и вот это всё);
— алгоритмы и структуры данных.

Скомпилировать успех

Акция до 31 декабря.
NullReferenceException при выборе? Пиши сюда: @manager_proglib
  • ❤ 3
  • 🥰 1
Post #6578 4.07K
⚙️ Один обработчик вместо сотни 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
  • ❤ 25
  • 👍 18
Post #6577 3.93K
  • 🥱 8
  • 🥰 3
Post #6576 4.2K
📊 Рейтинг постов

Вы всю неделю ставили нам лайки, а мы выбрали топ по реакциям:

• 100 RPS Rate Limiting
• Закон Брукса в разработке
• Антиспам в .NET
• FluentValidation в API
• StackTraceHiddenAttribute

Давайте выберем самый лучший пост в голосовании.

Что добавить в следующий спринт? Пишите! 👇


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

#entry_point
  • 🥰 5
  • 🔥 1
Post #6575 3.73K
Post #6574 3.96K
🔄 WSL 2.7.0: обновление с новым ядром

Windows Subsystem for Linux это встроенный слой совместимости, который позволяет запускать Linux и его приложения напрямую без виртуальной машины.

В WSL 2.7.0 ядро обновили до ветки Linux 6.6.114. Параллельно подтянули новые версии WSLg .NET и связанных NuGet пакетов.

Список поддерживаемых дистрибутивов пополнился свежими релизами: Debian 13, Ubuntu 25.10, Fedora 43, а также Kali 2025.3 и декабрьская сборка Arch Linux.

➡️ Релиз на GitHub

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

#async_news
  • ❤ 13
  • 🔥 4
Post #6573 4.19K
👨‍💻 Чистые стектрейсы в .NET с помощью StackTraceHiddenAttribute

В .NET есть простой способ скрыть внутреннюю кухню и оставить только то, что важно потребителю API. Атрибут StackTraceHiddenAttribute помечает методы, которые не должны попадать в публичный стектрейс, при этом логика выполнения не меняется.

Пример:
public static class UserService
{
[StackTraceHidden]
private static void ValidateName(string name)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Name cannot be empty");
}

public static void CreateUser(string name)
{
ValidateName(name);
Console.WriteLine("Created user " + name);
}
}


В этом примере при исключении из ValidateName в стектрейсе вы увидите только вызов UserService.CreateUser. Валидационный хелпер скрыт атрибутом, поэтому внешний разработчик не видит внутренний слой проверки.

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

#sharp_view
  • 👍 26
  • 🥰 3
  • ❤ 1
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →