Библиотека шарписта | C#, F#, .NET, ASP.NET
21.6K subscribers
2.9K photos
46 videos
91 files
5.38K links
Все самое полезное для C#-разработчика в одном канале.

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

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

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

РКН: https://gosuslugi.ru/snet/67a5c81cdc130259d5b7fead
Download Telegram
🧩 Middleware в ASP.NET Core: 3 ловушки

Middleware — звено HTTP pipeline:


app.Use(async (context, next) =>
{
Console.WriteLine("Request");

await next(context);

Console.WriteLine("Response");
});



1️⃣ Забыл next() — остановил pipeline


await _next(context);


Если его не вызвать, middleware ниже и endpoint не выполнятся.

2️⃣ Scoped-сервис не стоит инжектить в конструктор

Middleware переиспользуется между запросами, поэтому Scoped лучше получать в InvokeAsync:


public async Task InvokeAsync(
HttpContext context,
IMyScopedService service)
{
await _next(context);
}


3️⃣ После начала ответа менять его уже нельзя


await _next(context);

context.Response.StatusCode = 503; // 💥



Если response уже отправляется, будет InvalidOperationException.

💡 Для действий до отправки используйте Response.OnStarting().

И ещё: не передавайте scoped-сервис в Task.Run после завершения запроса — его scope уже мог быть уничтожен. Для фоновой работы создавайте новый scope или используйте BackgroundService 🧠

🔗 Источник

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

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

#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
💪 Разминка перед трудовыми буднями

Что произойдёт?

❤️ — список станет [1, 3]
🔥 — InvalidOperationException
👍 — цикл пропустит 2

Ответ спрячем здесь:

🔥 InvalidOperationException

foreach использует List<T>.Enumerator. После Remove() коллекция изменяется, перечислитель обнаруживает изменение при следующем MoveNext() и выбрасывает исключение.


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

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

#dotnet_challenge
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥65❤5👍1
⚙️ Настоящие атомарные операции

Если Volatile решает проблему видимости, то Interlocked решает проблему атомарности. Операции реализованы на уровне процессора и выполняются как неделимые единицы — никакой другой поток не может вмешаться в середину

➡️ Самый частый сценарий это счётчик, который обновляют несколько потоков:


private int _counter;

public void Increment()
{
Interlocked.Increment(ref _counter);
}


Без Interlocked операция _counter++ на самом деле три шага: прочитать, прибавить, записать. Два потока могут выполнить их одновременно и затереть результат друг друга. Interlocked.Increment делает всё это за один неделимый шаг.

➡️ Lock-free генератор ID

Interlocked подходит для генерации уникальных идентификаторов без блокировок:


public int GetNextId()
{
return Interlocked.Increment(ref _id);
}


Каждый вызов гарантированно вернёт уникальное значение, даже если тысячи потоков вызывают метод одновременно.

➡️ CompareExchange: условное обновление

Самая мощная операция в арсенале Interlocked:


if (Interlocked.CompareExchange(ref _state, 1, 0) == 0)
{
// Успешно перешли из состояния 0 в 1
}


Логика простая: если текущее значение равно 0, заменить на 1 и вернуть старое значение. Если кто-то уже изменил _state, операция ничего не сделает. Это паттерн, на котором строятся lock-free кэши, планировщики и конкурентные очереди.

➡️ Volatile и Interlocked — не одно и то же

Их можно перепутать, но они решают разные задачи.

Volatile гарантирует, что поток видит актуальное значение переменной. Interlocked гарантирует, что сама операция выполняется безопасно, без вмешательства других потоков.

В реальных системах нередко нужны оба. Volatile чтобы читать свежие данные, Interlocked чтобы безопасно их менять.

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

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8❤5🥰1
💡 Replace, Regex или StringBuilder?

Для замены текста в C# есть несколько инструментов. И выбирать их лучше не по принципу «что быстрее», а по задаче.

🔜 string.Replace() — когда ищем конкретный текст:


var result = text.Replace("cat", "dog");


🔜 Regex.Replace() — когда нужен шаблон:


var result = Regex.Replace(
text,
@"\d+",
"#");


Например, заменить все числа на #.

🔜 StringBuilder.Replace() — когда последовательно изменяем большой текст:


var sb = new StringBuilder(text);

sb.Replace("cat", "dog");
sb.Replace("foo", "bar");

var result = sb.ToString();


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

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥3❤2
⚙️ yield return не бесплатный

Итераторы выглядят просто, но работают иначе:


IEnumerable<int> GetIds()
{
foreach (var item in _items)
yield return item.Id;
}


Читается как обычный цикл. Но компилятор превращает такой метод в конечный автомат со вспомогательными классами и состоянием. Именно поэтому итераторы такие выразительные — но и именно поэтому они не бесплатны.

❓ Где это становится проблемой

На большинстве путей yield return это правильный выбор. Код чище, API удобнее, читаемость выше.

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

❓ Что делать на критичных участках

Если профилировщик показал, что итератор узкое место, есть несколько альтернатив.

🟡 Заполнение буфера, переданного вызывающей стороной:


void FillIds(Span<int> buffer)
{
for (int i = 0; i < _items.Count; i++)
buffer[i] = _items[i].Id;
}


🟡 Возврат конкретной коллекции:


List<int> GetIds()
{
var result = new List<int>(_items.Count);
foreach (var item in _items)
result.Add(item.Id);
return result;
}


🟡 Прямой цикл внутри горячего кода без промежуточных перечислений:


for (int i = 0; i < _items.Count; i++)
Process(_items[i].Id);


yield return стоит использовать тогда, когда он делает API лучше и код понятнее. Но не стоит считать его нулевым по стоимости. Если участок горячий, то сначала замерьте, потом решайте.

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

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

#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6❤3👍3😁1
🤩 Как поймать зависший .NET-сервис

Приложение начинает тормозить, запросы зависают, а в логах — ничего полезного? Можно автоматически снять memory dump в момент проблемы и потом разобрать состояние процесса.

➡️ Идея простая:



var task = Task.Run(() => { });

if (!task.Wait(3000))
{
// ThreadPool, вероятно, перегружен
// → создаём memory dump
}


➡️ Dump позволяет посмотреть:

— какие потоки зависли;
— где стоят Task;
— что происходит в ThreadPool;
— какие объекты находятся в памяти.

На Windows для создания dump можно использовать MiniDumpWriteDump, а в Linux — встроенный в .NET createdump. А дальше .dmp открывается в Visual Studio — можно исследовать call stacks, переменные и состояние потоков.

💡 Особенно полезно для production-проблем, которые невозможно нормально воспроизвести локально.

🔗 Источник

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

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤2👍1
🔐 NuGet: Microsoft меняет сертификат подписи

С 23 сентября Microsoft использует новый сертификат для подписи NuGet-пакетов. Если у вас настроен allowlist доверенных сертификатов, сборки могут начать падать с NU3034.

Что сделать:


dotnet nuget trust author Microsoft \
9A1B131BEE0605433056A4EA3815478A8E177961A968C6C0027C1093D1FEB630 \
--algorithm SHA256


Старые сертификаты удалять не нужно — они нужны для уже опубликованных пакетов.

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

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

#async_news
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤3👾1
👨‍💻 Не показывайте технические ошибки пользователям

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

⏬ Что происходит на практике

Допустим, в ASP.NET приложении возникает необработанное исключение. Без явной настройки middleware фреймворк вернёт подробный ExceptionDetails с именем метода, строкой кода и трассировкой стека. Атакующий получает информацию о структуре проекта, версиях библиотек и логике работы приложения без каких-либо усилий.

⏬ Как это закрыть

Правильный подход это перехват всех необработанныъ исключений. Нужно логировать их внутри системы и возвращать пользователю только нейтральное сообщение.

В ASP.NET это делается через UseExceptionHandler:


app.UseExceptionHandler(errorApp =>
{
errorApp.Run(async context =>
{
var exceptionHandlerPathFeature =
context.Features.Get<IExceptionHandlerPathFeature>();

var logger = context.RequestServices
.GetRequiredService<ILogger<Program>>();

logger.LogError(exceptionHandlerPathFeature?.Error,
"Unhandled exception");

context.Response.StatusCode = 500;

await context.Response.WriteAsJsonAsync(new
{
message = "Something went wrong. Please try again later."
});
});
});


⏬ Что здесь происходит

Middleware перехватывает исключение, передаёт его в ILogger — туда, где его увидит только команда разработки — и возвращает клиенту простой JSON с универсальным сообщением об ошибке. Никаких деталей реализации наружу не уходит.

ILogger пишет в вашу систему мониторинга — будь то Application Insights, Seq, Serilog или любой другой инструмент. Вы по-прежнему видите полный стек вызовов и можете разобраться в причине ошибки. Пользователь при этом получает понятное сообщение, а не технический мусор.

Это базовая практика защиты приложений. Она не требует сложной архитектуры, достаточно одного middleware, настроенного в точке входа приложения.

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

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

#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21
📝 Логирование со строковой интерполяцией

Логирование 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_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥18👍9❤2🤔1
🦈 Открытое собеседование на Middle C# | 6 октября, 19:00 МСК

Приглашаем на открытое собеседование: Senior C# разработчик проведёт его в прямом эфире. Можно посмотреть, как всё устроено изнутри, и понять, насколько ты готов к такому интервью.

Как это будет:
📂 Собеседует Александр Моргунов — Senior C# разработчик, 7+ лет в европейских высоконагруженных сервисах. Отвечает разработчик-доброволец;

📂 Всё как на настоящем собесе: Александр задаёт те вопросы и задачи, которые даёт кандидатам на своих интервью. Заранее их никто не знает;

📂 После каждого ответа Александр даст обратную связь: что прозвучало сильно, а что стоило раскрыть иначе. Так станет понятнее, на что обращают внимание на собесе;

📂 В конце можно задать любой вопрос.

Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для C# разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.

Переходи в нашего бота, чтобы получить ссылку на эфир -> @shortcut_csharp_bot

Реклама.
О рекламодателе.
👍5❤1