Фильтр публикаций


Как ограничить количество запросов к API по IP в ASP.NET Core

Встроенный Rate Limiter позволяет сделать это буквально в несколько строк:


builder.Services.AddRateLimiter(options =>
{
options.AddPolicy("fixed-by-ip", httpContext =>
RateLimitPartition.GetFixedWindowLimiter(
partitionKey: httpContext.Connection.RemoteIpAddress?.ToString(),
factory: _ => new FixedWindowRateLimiterOptions
{
PermitLimit = 10,
Window = TimeSpan.FromMinutes(1)
}));
});


В этом примере один IP может сделать максимум 10 запросов за минуту.

Но использовать такой подход вслепую не стоит.

Причина простая: реальные пользователи могут находиться за NAT, прокси или корпоративным шлюзом и иметь один внешний IP. В итоге лимит одного человека начнёт влиять на остальных.

Поэтому для авторизованных пользователей обычно лучше ограничивать запросы по уникальному userId.

А rate limit по IP оставлять для анонимных endpoint'ов, защиты от простых ботов или как дополнительный слой защиты.


⚡️Актуальные темы .NET на DotNext 2026

В .NET одновременно происходит много интересного: C# получает новые возможности, .NET 10 меняет расклад между Native AOT и JIT, а в разработке появляются ИИ-агенты, которые берут на себя часть инженерной работы.
На DotNext 2026 разберем как вещи, которые происходят на уровне машинного кода, так и вполне прикладные вопросы архитектуры и разработки.

📅 25–26 сентября, Москва + online

Выбрали 8 тем из программы, среди которых не только доклады, но и хардкорный воркшоп, чтобы показать этот диапазон:

— как заставить Transactional Outbox одновременно быть строгим и параллельным;
— зачем ASP.NET Core модульный монолит и как собрать его без микросервисов;
— где Native AOT выигрывает у JIT в .NET 10;
— что происходит с циклами, inlining и bounds checks в C# и Go;
— как меняется SDLC, когда в команде появляются ИИ-агенты;
— что принесут discriminated unions в C# 15;
— как проектировать асинхронное взаимодействие в распределенных системах (воркшоп).

Все подробности — в карточках и на сайте конференции.

🌟По промокоду csharpci — персональные билеты дешевле

Программа DotNext

Купить билет


Появился бесплатный open-source PDF-редактор для Windows, который пытается заменить Adobe Acrobat без подписки.

KillerPDF умеет редактировать текст прямо в PDF, добавлять аннотации и изображения, объединять и разделять страницы, заполнять формы, ставить подписи, печатать и делать OCR. Причём распознавание работает локально через Tesseract, без отправки документов в облако.

Есть и более редкие штуки: восстановление повреждённых PDF, открытие файлов с паролем, выравнивание кривых сканов, perspective correction, ночной режим, split view для двух документов и полноценная работа из командной строки.

Весь редактор упакован примерно в 16 МБ, может работать portable, не требует аккаунта, не собирает телеметрию и не делает phone-home. Проект распространяется под GPLv3.

На GitHub уже около 3,4 тыс. звёзд.

https://github.com/SteveTheKiller/KillerPDF


🔥 Хочешь быстрее расти в IT? Хватит учиться в одиночку

Окружение решает больше, чем кажется.

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

AI: t.me/ai_machinelearning_big_data
Python: t.me/pythonl
Linux: t.me/linuxacademiya
Хакинг: t.me/linuxkalii
DevOps: t.me/DevOPSitsec
Docker: https://t.me/+90Z5TAyfuNU5YmRi
Golang: t.me/Golang_google
Rust: t.me/rust_code
C++: t.me/cpluspluc
C#: t.me/csharp_1001_notes
Java: t.me/javatg
JavaScript: t.me/javascriptv
React: t.me/react_tg
Frontend: t.me/front
PHP: t.me/phpshka
Android: t.me/android_its
Мобильная разработка: t.me/mobdevelop
Базы данных: t.me/sqlhub
Data Science: t.me/data_analysis_ml
Big Data: t.me/bigdatai
Математика: t.me/data_math
Физика: https://t.me/+S4hinvO3QI43ZjNi
Kubernetes: t.me/kubernetc
GameDev: https://t.me/gamedev
Haskell: t.me/haskell_tg

Собеседования и карьера:

DS собеседования: t.me/machinelearning_interview
Python собеседования: t.me/python_job_interview

Папка с вакансиями: t.me/addlist/_zyy_jQ_QUsyM2Vi
Папка Go разработчика: t.me/addlist/MUtJEeJSxeY2YTFi
Папка Python разработчика: t.me/addlist/eEPya-HF6mkxMGIy
Папка ML: 'https://t.me/addlist/2Ls-snqEeytkMDgy' rel='nofollow'>https://t.me/addlist/2Ls-snqEeytkMDgy
Папка Frontend: https://t.me/addlist/mzMMG3RPZhY2M2Iy

Полезное сверху:

ИТ-мемы: t.me/memes_prog
Английский для программистов: t.me/english_forprogrammers
ИИ и технологии: t.me/vistehno
954 ГБ open-source курсов: https://t.me/+rKBQEMccAA01MTcy
ИТ-книги бесплатно: https://t.me/addlist/BkskQciUW_FhNjEy

Max Ai: https://max.ru/ai_machinelearning_big_data
Max python: https://max.ru/pythonl
ТЕХНО: https://max.ru/vistehno
Max Go: https://max.ru/Golang_google
Max Linux: https://max.ru/linuxkalii
Devops: https://max.ru/DevOPSitsec
C#: https://max.ru/csharp_ci
C++: https://max.ru/cpluspluc
SQL: https://max.ru/sqlhub
Java: https://max.ru/javatg

Подписывайся на нужные направления и собирай себе ленту, которая реально двигает вперёд.


#ПятничныйКвиз


⚙️ Service Discovery в .NET через Consul можно подключить без самописного резолва адресов и ручного перебора инстансов.

Рабочая схема выглядит так:


Install-Package Steeltoe.Discovery.Consul


Регистрируем discovery:


builder.Services
.AddServiceDiscovery(o => o.UseConsul());


В appsettings.json указываем Consul и параметры сервиса:


"Consul": {
"Host": "localhost",
"Port": 8500,
"Discovery": {
"ServiceName": "reporting-service",
"Hostname": "reporting-api",
"Port": 8080
}
}


А дальше самое полезное:


builder.Services
.AddHttpClient(client =>
{
client.BaseAddress = new Uri("http://reporting-service");
})
.AddServiceDiscovery()
.AddRoundRobinLoadBalancer();


То есть HttpClient ходит не на конкретный IP:port, а на логическое имя сервиса.

Steeltoe через Consul получает живые инстансы, а RoundRobinLoadBalancer распределяет запросы между ними.

Это особенно полезно, когда сервисы часто пересоздаются, IP меняются, а хардкодить адреса уже невозможно.

По сути, клиентская часть получает простой pipeline:

service name → Consul → healthy instances → load balancing → HTTP request

Для микросервисов на .NET это намного чище, чем городить собственный discovery layer.


🔥 .NET 11 Preview 7 вышел, и Microsoft заметно прокачала сразу C#, Runtime, ASP.NET Core и SDK

Один из самых интересных апдейтов в C# — labeled break и continue: теперь можно явно указать, из какого цикла выходить или какой цикл продолжать. Ещё появились union patterns и улучшенная проверка исчерпывающих случаев для закрытых иерархий типов.

В Runtime добавили оптимизации async`/`await, включая runtime async tiering и tail-await. Отдельно продолжают развивать NativeAOT и JIT.

В SDK NativeAOT-версия dotnet CLI теперь включена по умолчанию, как и MSBuild Server. У dotnet test появились общий --timeout, ограничение --maximum-failed-tests и поддержка запуска тестов на устройствах .NET MAUI.

ASP.NET Core получил автоматическую приостановку неактивных Blazor circuits, кеширование SSR через CacheView, новые анализаторы Blazor и встроенную локализацию validation-сообщений.

Ещё из приятного: HTTP request compression, API для DNS-записей, парольная защита ZIP, Complex, улучшения LINQ в EF Core и поддержка Half в SQLite.

.NET 11 Preview 7 вышел 11 августа 2026 года и уже доступен для тестирования.

https://devblogs.microsoft.com/dotnet/dotnet-11-preview-7/


#ПятничныйКвиз #ДляСамыхМаленьких


🚀 C# РАЗРАБОТЧИКИ: перестаньте создавать зависимости вручную

Одна из самых частых ошибок в архитектуре .NET - создавать зависимости прямо внутри класса.

❌ Плохой подход:
var companyRepository = new CompanyRepository();
var customerRepository = new CustomerRepository();
var creditService = new CustomerCreditServiceClient();
Проблемы:

❌ жёсткая связность компонентов
❌ сложно заменить реализацию
❌ трудно писать unit-тесты
❌ нет удобного контроля времени жизни объектов

✅ Лучше использовать Dependency Injection
public class CustomerService(
CompanyRepository companyRepository,
CustomerRepository customerRepository,
CustomerCreditServiceClient creditService)
{
}
Теперь DI-контейнер сам создаёт и передаёт нужные зависимости.

Преимущества:

✅ управление временем жизни (Singleton, Scoped, Transient)
✅ лёгкое использование mock-объектов в тестах
✅ decorators для логирования, кэширования и retry
✅ меньше связности между классами
✅ проще масштабировать и рефакторить проект

Dependency Injection - это не просто возможность ASP.NET Core.

Это один из главных принципов создания чистой, гибкой и поддерживаемой архитектуры C#.

🔥 Ещё 5 приёмов рефакторинга C#, которые стоит знать каждому .NET разработчику:
https://milanjovanovic.tech/blog/5-awesome-csharp-refactoring-tips


Запрограммируй робота на Python и поборись за призовой фонд трека 7 500 000 руб на True Tech Champ 2026.

Попробуй себя в треке по программированию роботов. Начать проще, чем кажется: зарегистрируйся, собери команду или объединись с другими участниками на платформе и пройди квалификационный этап до 13 сентября. В онлайн-симуляторе тебе предстоит запрограммировать робособаку и робота-манипулятора для доставки груза через полосу препятствий. Количество попыток не ограничено, а еще тебя будет ждать серия обучающих вебинаров.

Лучшие команды пройдут в финал и будут программировать реальных роботов на офлайн-полигоне 22 октября на большой сцене.
Масштабный финал объединит борьбу за призовой фонд, выступления хедлайнеров, доклады спикеров и активности для всех гостей мероприятия.

Рекомендуемые стеки: Go, Java, Python, C#, C++, JS.

Успей зарегистрироваться и пройти квалификацию до 13 сентября

Реклама. ООО "МВС", ИНН 7707767501, Erid:2VSb5yvnNti


💡 C#: заставьте архитектуру ломать CI, если кто-то нарушил правила

Компилятор C# отлично проверяет типы, но ему всё равно, что Application внезапно начал зависеть от Infrastructure.

Code Review тоже не гарантирует, что такое заметят.

Для этого можно использовать Architecture Tests — тесты, которые проверяют не бизнес-логику, а структуру проекта.

Например, через NetArchTest.Rules:


[Fact]
public void Application_Should_Not_Depend_On_Infrastructure()
{
var result = Types
.InAssembly(ApplicationAssembly)
.ShouldNot()
.HaveDependencyOn("MyApp.Infrastructure")
.GetResult();

Assert.True(result.IsSuccessful);
}


Теперь случайный:


Application → Infrastructure


сломает CI так же, как обычный упавший unit-тест.

Можно зафиксировать и naming convention:


[Fact]
public void Handlers_Should_End_With_Handler()
{
var result = Types
.InAssembly(ApplicationAssembly)
.That()
.ImplementInterface(typeof(ICommandHandler))
.Should()
.HaveNameEndingWith("Handler")
.GetResult();

Assert.True(result.IsSuccessful);
}


Или заставить сервисы быть sealed:


Types
.InAssembly(ApplicationAssembly)
.That()
.HaveNameEndingWith("Service")
.Should()
.BeSealed();


Особенно полезно это становится в больших Clean Architecture / DDD / Modular Monolith проектах.

Вместо документа:


❌ «Application не должен зависеть от Infrastructure»


получаем исполняемое правило:


✅ нарушил архитектуру → тест упал → PR не прошёл


По сути, архитектура превращается из договорённости команды в часть автоматической проверки проекта.

#CSharp #DotNet #Architecture #Testing


#ПятничныйКвиз


🔥 Request-response через брокер сообщений в C#: мощный паттерн, который легко превратить в распределённый дедлок

Один сервис отправляет сообщение в RabbitMQ или NATS и ждёт ответ.

Для вызывающего кода это выглядит почти как обычный await, хотя под капотом работают две независимые очереди:


Requester -> request -> Responder
Requester


Лето, ИТ-Пикник и музыка известных артистов уже через несколько дней!

8 августа в Коломенском пройдет ИТ-Пикник.

В программе — выступления проекта LAB Антона Беляева, IOWA, Cream Soda, Pompeya, мартина и Совы.

А днем — научпоп-лекции, дискуссии об ИИ и больших языковых моделях, мастер-классы и интерактивы. Полезные знакомства и развлечения тоже будут.

Зарегистрироваться и узнать подробности можно на сайте мероприятия.

В билет входит +1 — можно позвать близких и друзей.

До встречи в месте притяжения ИТ.


## В C# появился safe — но это не аналог Rust

В C# 15 тестируется новый контекстный модификатор safe для кода на границе с нативной памятью.

Главная проблема P/Invoke: компилятор видит сигнатуру метода, но не может проверить, насколько безопасно ведёт себя код внутри подключённой библиотеки. Теперь разработчик должен явно зафиксировать решение:


[LibraryImport("libc")]
internal static safe partial int getpid();

[LibraryImport("libc")]
internal static unsafe partial nuint strlen(byte* value);


safe означает, что вызов не требует `unsafe`-контекста со стороны пользователя API.

unsafe предупреждает: безопасность зависит от условий, которые компилятор проверить не может. Такой метод разрешено вызывать только внутри блока:


unsafe
{
nuint length = strlen(pointer);
}


Та же логика применяется к полям структур с явным расположением памяти:


[StructLayout(LayoutKind.Explicit)]
struct Packet
{
[FieldOffset(0)]
public safe long Id;

[FieldOffset(0)]
public unsafe nint Pointer;
}


Если не указать ни safe, ни unsafe, компилятор выдаст ошибку при включённых новых правилах безопасности. :contentReference[oaicite:0]{index=0}

Важный нюанс: safe не анализирует нативный код и не доказывает его безопасность. Это явное обещание автора API, которое делает потенциально опасные границы заметными при ревью.

C# постепенно меняет подход к unsafe: риск должен быть обозначен в контракте метода и локализован в конкретных участках программы, а не спрятан внутри большого `unsafe`-класса.

Пока эта модель находится в preview и может измениться до стабильного выпуска C# 15.


C#-приём: точное сложение `double` через алгоритм Кэхэна

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

Обычный вариант:


double sum = 0;

foreach (double value in values)
{
sum += value;
}


Более точный вариант:


public static double KahanSum(ReadOnlySpan values)
{
double sum = 0;
double compensation = 0;

foreach (double value in values)
{
double adjusted = value - compensation;
double next = sum + adjusted;

compensation = (next - sum) - adjusted;
sum = next;
}

return sum;
}


Переменная compensation сохраняет часть числа, потерянную при округлении, и возвращает её в следующее сложение.

Использование:


double[] values = { 0.1, 0.2, 0.3, 0.4 };

double result = KahanSum(values);


Метод полезен для:

- научных расчётов;
- статистики и аналитики;
- обработки сигналов;
- симуляций;
- накопления миллионов небольших значений.

ReadOnlySpan позволяет передавать массивы и участки памяти без дополнительных копирований.

Алгоритм требует нескольких дополнительных операций на каждом шаге, зато заметно уменьшает накопленную погрешность.

Для денежных расчётов по-прежнему лучше использовать decimal. А когда нужна скорость double и повышенная численная устойчивость – пригодится Kahan Summation.


C# 15 наконец избавляет вложенные циклы от флагов и `goto`

break и continue могут указывать метку внешнего цикла. Это позволяет сразу выйти из нескольких уровней вложенности или перейти к следующей итерации нужного цикла.


outer: for (int row = 0; row < grid.Height; row++)
{
for (int column = 0; column < grid.Width; column++)
{
if (grid[row, column].IsBlocked)
{
continue outer;
}

if (grid[row, column].IsGoal)
{
break outer;
}
}
}


Здесь:

- continue outer прекращает внутренний цикл и запускает следующую итерацию внешнего;
- break outer полностью выходит из обоих циклов.

Раньше для такого поведения приходилось использовать булевы флаги, дополнительные проверки или goto.

В C# 15 этот код можно записать короче и понятнее.

Особенно удобно при обходе:

- матриц;
- вложенных коллекций;
- игровых карт;
- таблиц;
- сложных структур данных.

Небольшое изменение, которое убирает много лишнего кода из вложенных циклов.


#ПятничныйКвиз


Clean Code: сложный `if` лучше превратить в понятное правило

Такой код приходится расшифровывать каждый раз:


if (invoice is not null &&
invoice.Status == InvoiceStatus.Unpaid &&
invoice.DueDateUtc < DateTime.UtcNow &&
invoice.Balance > 0 &&
!invoice.SilenceWarnings &&
invoice.Customer.Email is not null)
{
SendOverdueWarning(invoice);
}


Условие растёт, бизнес-правило теряется среди технических деталей, а изменение одного требования превращается в рискованный рефакторинг.

Вынесем правило в метод с говорящим именем:


if (invoice.ShouldSendOverdueWarning(nowUtc))
{
SendOverdueWarning(invoice);
}


Само правило:


public bool ShouldSendOverdueWarning(DateTime nowUtc)
{
return Status == InvoiceStatus.Unpaid
&& DueDateUtc < nowUtc
&& Balance > 0
&& !SilenceWarnings
&& Customer.Email is not null;
}


Теперь вызывающий код отвечает на вопрос что происходит, а метод хранит детали когда это разрешено.

### Почему исходный вариант плохо тестируется

Он напрямую использует DateTime.UtcNow. Результат зависит от реального времени, поэтому тест может вести себя по-разному в разные моменты.

После передачи времени параметром тест становится предсказуемым:


[Fact]
public void Sends_warning_for_overdue_unpaid_invoice()
{
var invoice = new Invoice
{
Status = InvoiceStatus.Unpaid,
DueDateUtc = new DateTime(2026, 7, 20),
Balance = 1500,
SilenceWarnings = false,
Customer = new Customer { Email = "user@example.com" }
};

var nowUtc = new DateTime(2026, 7, 28);

Assert.True(invoice.ShouldSendOverdueWarning(nowUtc));
}


Для больших проектов вместо DateTime можно внедрить TimeProvider. Главное правило: время, сеть, файловая система и случайность не должны быть скрыты внутри бизнес-логики.


Copilot научили разбирать MSBuild-логи прямо в VS Code

Microsoft выпустила MSBuild Binlog Analyzer — расширение, которое превращает сложные .binlog в понятный диалог с GitHub Copilot.

Можно спросить:

почему упала сборка;
какие targets и tasks тормозят;
что изменилось между двумя сборками;
почему сломалась incremental build.

Copilot опирается на реальные данные лога через MCP, умеет находить причину ошибки, предлагать исправление и проверять результат повторной сборкой. Есть сравнение с baseline, поиск регрессий и загрузка логов из GitHub Actions и Azure DevOps.

https://devblogs.microsoft.com/dotnet/msbuild-binlog-analyzer-vscode/

Показано 20 последних публикаций.