.NET Core: 3 ловушкиMiddleware — звено HTTP pipeline:
app.Use(async (context, next) =>
{
Console.WriteLine("Request");
await next(context);
Console.WriteLine("Response");
});
await _next(context);
Если его не вызвать, middleware ниже и endpoint не выполнятся.
Middleware переиспользуется между запросами, поэтому Scoped лучше получать в InvokeAsync:
public async Task InvokeAsync(
HttpContext context,
IMyScopedService service)
{
await _next(context);
}
await _next(context);
context.Response.StatusCode = 503; // 💥
Если response уже отправляется, будет InvalidOperationException.
И ещё: не передавайте scoped-сервис в Task.Run после завершения запроса — его scope уже мог быть уничтожен. Для фоновой работы создавайте новый scope или используйте BackgroundService
📍 Навигация: Вакансии • Задачи • Собесы
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Что произойдёт?
❤️ — список станет [1, 3]
🔥 — InvalidOperationException
👍 — цикл пропустит 2
Ответ спрячем здесь:
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 делает всё это за один неделимый шаг.
Interlocked подходит для генерации уникальных идентификаторов без блокировок:
public int GetNextId()
{
return Interlocked.Increment(ref _id);
}
Каждый вызов гарантированно вернёт уникальное значение, даже если тысячи потоков вызывают метод одновременно.
Самая мощная операция в арсенале Interlocked:
if (Interlocked.CompareExchange(ref _state, 1, 0) == 0)
{
// Успешно перешли из состояния 0 в 1
}
Логика простая: если текущее значение равно 0, заменить на 1 и вернуть старое значение. Если кто-то уже изменил _state, операция ничего не сделает. Это паттерн, на котором строятся lock-free кэши, планировщики и конкурентные очереди.
Их можно перепутать, но они решают разные задачи.
Volatile гарантирует, что поток видит актуальное значение переменной. Interlocked гарантирует, что сама операция выполняется безопасно, без вмешательства других потоков.
В реальных системах нередко нужны оба. Volatile чтобы читать свежие данные, Interlocked чтобы безопасно их менять.
📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8❤5🥰1
Для замены текста в C# есть несколько инструментов. И выбирать их лучше не по принципу «что быстрее», а по задаче.
var result = text.Replace("cat", "dog");
var result = Regex.Replace(
text,
@"\d+",
"#");
Например, заменить все числа на #.
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
Итераторы выглядят просто, но работают иначе:
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
Приложение начинает тормозить, запросы зависают, а в логах — ничего полезного? Можно автоматически снять memory dump в момент проблемы и потом разобрать состояние процесса.
var task = Task.Run(() => { });
if (!task.Wait(3000))
{
// ThreadPool, вероятно, перегружен
// → создаём memory dump
}
— какие потоки зависли;
— где стоят Task;
— что происходит в ThreadPool;
— какие объекты находятся в памяти.
На Windows для создания dump можно использовать MiniDumpWriteDump, а в Linux — встроенный в .NET createdump. А дальше .dmp открывается в Visual Studio — можно исследовать call stacks, переменные и состояние потоков.
📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤2👍1
🔐 NuGet: Microsoft меняет сертификат подписи
С 23 сентября Microsoft использует новый сертификат для подписи NuGet-пакетов. Если у вас настроен allowlist доверенных сертификатов, сборки могут начать падать с NU3034.
Что сделать:
Старые сертификаты удалять не нужно — они нужны для уже опубликованных пакетов.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#async_news
С 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 как по полю, а не парсить текст.
// Генерирует оптимальный код на этапе компиляции:
[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
Реклама.
О рекламодателе.
Приглашаем на открытое собеседование: Senior C# разработчик проведёт его в прямом эфире. Можно посмотреть, как всё устроено изнутри, и понять, насколько ты готов к такому интервью.
Как это будет:
📂 Собеседует Александр Моргунов — Senior C# разработчик, 7+ лет в европейских высоконагруженных сервисах. Отвечает разработчик-доброволец;
📂 Всё как на настоящем собесе: Александр задаёт те вопросы и задачи, которые даёт кандидатам на своих интервью. Заранее их никто не знает;
📂 После каждого ответа Александр даст обратную связь: что прозвучало сильно, а что стоило раскрыть иначе. Так станет понятнее, на что обращают внимание на собесе;
📂 В конце можно задать любой вопрос.
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для C# разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир -> @shortcut_csharp_bot
Реклама.
О рекламодателе.
👍5❤1