С днем программиста, коллеги!
Желаем, чтобы код компилировался с первого раза, баги находились до релиза, а таски «на пять минут» действительно занимали пять минут.
И конечно, пусть в жизни будет больше приятных сюрпризов — один из них мы уже подготовили. Скорее переходите по ссылке, трясите коробку и забирайте свой подарок ко Дню программиста: https://tprg.ru/YtJ2
Желаем, чтобы код компилировался с первого раза, баги находились до релиза, а таски «на пять минут» действительно занимали пять минут.
И конечно, пусть в жизни будет больше приятных сюрпризов — один из них мы уже подготовили. Скорее переходите по ссылке, трясите коробку и забирайте свой подарок ко Дню программиста: https://tprg.ru/YtJ2
🥰15❤9🎉4👍1
.NET Core на .NET 11В C# 15 можно описать тип с несколькими допустимыми вариантами:
public union IntOrString(int, string);
Такой endpoint может вернуть либо число, либо строку:
app.MapGet("/max-unavailable", () => new IntOrString(2));
JSON останется обычным:
2
или:
"25%"
Без $type и дополнительных обёрток.
Главный плюс — компилятор проверяет, что switch обработал все варианты union.
Поддерживается в Minimal APIs, MVC, SignalR, Blazor и OpenAPI.
📍 Навигация: Вакансии • Задачи • Собесы
#async_news
Please open Telegram to view this post
VIEW IN TELEGRAM
❤🔥21❤3
Разберём на вебинаре, как тратить меньше на AI-агентов — без потери качества кода.
— когда дорогая модель действительно нужна, а когда хватит дешёвой;
— сколько стоит один прогон и куда уходят токены;
— какие задачи можно отдавать субагентам;
— как настроить маршрутизацию моделей;
— что проверять в AI-коде перед merge.
Please open Telegram to view this post
VIEW IN TELEGRAM
😁4🥱2🔥1
🧑💻 Забытый await: от race condition до DoS-атаки
В C# ключевое слово async — это инструкция компилятору превратить метод в state machine. await отмечает точку логической приостановки. Всё просто: выполнение не должно продолжаться, пока результат не существует.
При await весь код выполняется синхронно, пока не достигнет I/O или функции, возвращающей Task. Если Task не завершён, происходит раскрутка кадра стека, и поскольку обрамляющие методы приостановлены до самого верха, поток может быть освобождён в пул потоков.
Позже задача завершается, продолжение планируется и выполнение возобновляется там, где остановилось. Это не параллельное выполнение, это приостановка и возобновление.
Если забыли await:
Это режим «запустил и забыл» (fire-and-forget). Последствия:
• выполнение продолжается немедленно
• зависимость не обеспечивается
• исключения выходят за пределы логического стека вызовов
Что может произойти с приложением
⚠️ Забытый await может привести к классическому состоянию гонки: код продолжает выполнение до завершения критической операции, например, проверки прав доступа, открывая окно для эксплуатации.
Атакующий может успеть получить доступ к данным между моментом начала проверки и её завершением.
⚠️ Когда исключения выходят за пределы логического стека вызовов, они могут быть проглочены без логирования. Это маскирует неудачные попытки аутентификации, SQL-инъекции или другие атаки.
⚠️ Истощение пула потоков как вектор DoS-атаки. При высокой нагрузке неправильное использование async/await приводит к истощению пула потоков. Злоумышленник может намеренно генерировать запросы, эксплуатирующие блокирующие операции.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#il_люминатор
В C# ключевое слово async — это инструкция компилятору превратить метод в state machine. await отмечает точку логической приостановки. Всё просто: выполнение не должно продолжаться, пока результат не существует.
При await весь код выполняется синхронно, пока не достигнет I/O или функции, возвращающей Task. Если Task не завершён, происходит раскрутка кадра стека, и поскольку обрамляющие методы приостановлены до самого верха, поток может быть освобождён в пул потоков.
Позже задача завершается, продолжение планируется и выполнение возобновляется там, где остановилось. Это не параллельное выполнение, это приостановка и возобновление.
Если забыли await:
var task = GetDataAsync();
// забыли await
Use(task);
Это режим «запустил и забыл» (fire-and-forget). Последствия:
• выполнение продолжается немедленно
• зависимость не обеспечивается
• исключения выходят за пределы логического стека вызовов
Что может произойти с приложением
Атакующий может успеть получить доступ к данным между моментом начала проверки и её завершением.
📍 Навигация: Вакансии • Задачи • Собесы
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍4😁2🥱2
kubectl top pod показывает 1 ГБ, а managed heap занимает всего 300 МБ. Куда делись остальные 700?
Память .NET-процесса — это не только GC:
— managed heap;
— JIT и загруженные сборки;
— стеки потоков;
— native-библиотеки;
— буферы сокетов;
— runtime и TLS.
Поэтому одного GCHeapHardLimitPercent недостаточно: он ограничивает только managed heap.
kubectl top pod
dotnet-counters monitor -p <pid> System.Runtime
dotnet-gcdump collect -p <pid>
dotnet-dump collect -p <pid>
→ не выставляй всем подам одинаковые memory limits;
→ проверь AsNoTracking() и проекции в EF Core;
→ ищи .Result, .Wait() и блокирующий I/O;
→ тестируй GC под реальным memory limit контейнера.
📍 Навигация: Вакансии • Задачи • Собесы
#il_люминатор
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👾1
В TypeScript достаточно, чтобы у объекта был нужный метод:
function foo(a: { Do(): void }) {
a.Do();
}
class A
{
public void Do() => Console.WriteLine("A.Do");
}
class B
{
public void Do() => Console.WriteLine("B.Do");
}
Foo(new A());
Foo(new B());
И здесь на сцену выходят interceptors — экспериментальная возможность компилятора C#.
[DuckShape]
public interface IDoable
{
void Do();
}
public static partial class Ops
{
[DuckTyped]
public static void Foo(IDoable value)
=> value.Do();
}
internal readonly struct ShapeAdapter_IDoable_A : IDoable
{
private readonly A _value;
public ShapeAdapter_IDoable_A(A value)
=> _value = value;
public void Do() => _value.Do();
}
А interceptor подменяет вызов и оборачивает A или B в подходящий адаптер.
Ops.Foo(new A()); // A.Do
Ops.Foo(new B()); // B.Do
Работает и с properties — например, можно описать INameable с Name { get; set; }, а затем передать обычный Person, не меняя его код.
⚠️ Но это скорее интересный PoC, чем готовая замена интерфейсам:
— interceptors остаются экспериментальной возможностью;
— нужен source generator;
— есть ограничения и не покрытые edge cases;
— появляется дополнительная магия на этапе компиляции.
📍 Навигация: Вакансии • Задачи • Собесы
#sharp_view
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4❤2👍2
.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
👍7
Что произойдёт?
❤️ — список станет [1, 3]
🔥 — InvalidOperationException
👍 — цикл пропустит 2
Ответ спрячем здесь:
foreach использует List<T>.Enumerator. После Remove() коллекция изменяется, перечислитель обнаруживает изменение при следующем MoveNext() и выбрасывает исключение.
📍 Навигация: Вакансии • Задачи • Собесы
#dotnet_challenge
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥59❤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
🔥7❤4🥰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
👍6🔥3❤2