AS4 в.NET без Java‑шлюза: ebMS 3.0, WS‑Security и неотрекаемые квитанции шагом маршрута

AS4: подписанный и зашифрованный обмен документами с гос- и корпоративными системами ЕС. Теперь нативный коннектор redb.Route, без Java MSH.
Если искать ...

Хаб со знаниями про .NET

AS4: подписанный и зашифрованный обмен документами с гос- и корпоративными системами ЕС. Теперь нативный коннектор redb.Route, без Java MSH.
Если искать ...

Меня зовут Кирилл, я работаю BIM‑координатором, писал эту статью совместно со своей коллегой Анастасией. Помучавшись с разработкой ЦИМ без какой‑либо автоматизации, вместе мы подготовили плагин IDS Core. В этой статье — проблемы, которые нас натолкнули на создание нужных инструментов.
Мы оба давно работаем в BIM, и в начале 2026 года перед нами появилась новая задача: нужно было научиться стабильно готовить модели в IFC под новые требования ДГП.
С января 2026 года архитектурно‑градостроительные решения в Москве сдаются вместе с цифровой информационной моделью в IFC. Требования к ней описаны машиночитаемо — файлами IDS, проверяет их сервис «Строим просто». Схема, в общем, понятная. Пока не начнёшь ей пользоваться.

Выложу здесь в одну статью серию постов из моего ТГ канала про то, как в этом году прошёл DotNext.
25 и 26 сентября в Москве прошла очередная конференция DotNext. Вернулся и делюсь впечатлениями. Я уже писал, какие доклады хочу посетить, однако, по ходу несколько раз передумал. На этот раз решил посетить несколько воркшопов, т.к. они не записываются на видео, а доклады можно посмотреть в записи позже. Воркшоп отличается от доклада тем, что на нём разбирается конкретный практический пример, а аудитория активно участвует, задавая вопросы или предлагая решения. Раньше они меня пугали своей продолжительностью. Доклады длятся по часу, а воркшоп – это обычно от полутора часов и дольше. ИЧСХ, в начале каждого воркшопа любой докладчик считает своим долгом упомянуть, что времени у нас очень мало 😉. Хочу признать, что я много потерял, не посещая воркшопы раньше. Это отличный опыт практики и командной работы.
Первым был воркшоп от Андрея Цветцих (они с братом Денисом завсегдатаи различных конференций) «Паттерны асинхронного взаимодействия в распределенных системах». Мы разбирали пример реализации сервиса уведомлений (например, по e-mail) о событиях. Как настроить передачу информации в сервис рассылки? Какие данные передавать? Как реализовать гарантии доставки и избежать отправки дублирующих сообщений? Возможно ли реализовать доставку «exactly-once»? Интересно, что здесь нет единственно верного решения. Каждое решение – компромисс со своими плюсами и минусами.

В .NET 9 появился новый примитив синхронизации System.Threading.Lock, и многие команды начали заменять привычные object-замки на новый тип в поисках более предсказуемого поведения и производительности. Но такая замена меняет саму механику работы lock: достаточно одного места, где экземпляр потеряет свой тип, чтобы два участка кода перестали синхронизироваться между собой.
В статье разберемся, как именно устроена новая модель блокировок в C#, где компилятор помогает заметить проблему, а где она остаётся скрытой, и стоит ли переходить на Lock ради заявленных преимуществ.

Мы привыкли, что ограничения (CONSTRAINT) — это способ указания допустимых значений для столбцов, ограничение уникальности и создание связей между таблицами. Это отличный способ поддерживать целостность данных, предотвращая некорректные операции. Но помимо этого, ограничения также помогают оптимизатору запросов генерировать более эффективный план выполнения. Как именно? Читайте ниже.
Дисклеймер. Все описанное выполнялось в изолированной лаборатории на вымышленном приложении, которое я собрал специально для статьи. Совпадения имен с реальными продуктами случайны. Материал образовательный — для AppSec, .NET-разработчиков и всех, кому интересно, как «сохранить объект в файл» превращается в удаленное выполнение кода. Не применяйте это к системам, на которые у вас нет письменного разрешения.
Есть распространенный страх: анализ защищенности — это что-то темное, для избранных, с ассемблером и магией. На деле большая часть работы — это чтение кода по понятным правилам. Сейчас разберем реальный по механике баг (небезопасная десериализация в .NET → выполнение произвольной команды) так, будто читаем букварь: сначала буквы, потом слоги, потом целые слова.
К концу статьи вы будете уметь: декомпилировать .NET-приложение, находить в нем точки сериализации и десериализации, читать свойства и сеттеры, отличать безобидный класс от «gadget» и по одной строчке понимать, есть ли уязвимость. Все воспроизводится на приложенном стенде.
Про цвет. Листинги с подсветкой даны картинками. Цвета: желтый — имя класса/тип, синий — имя свойства, зеленый — значение (данные), красный — опасное место (sink, уязвимая строка, побочный эффект). В «было/стало» красный — что убираем, зеленый — что ставим.

На wine.co.za данные хранятся в MariaDB, раз в день копируются в Manticore, а сайт обращается к поиску через библиотеку для .NET. Разбираем, как устроен поиск по архиву из примерно 145 тысяч записей и что изменилось для посетителей и небольшой ИТ-команды.

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

Каждый день в 18:00 клиентам становится доступна отчётность по продажам, и многие одновременно нажимают кнопку «Загрузить отчёт». Это может быть детализированный отчёт по списаниям, юридическая отчётность, аналитическая выгрузка или API, используя который клиент получает данные для дальнейшей обработки. В этот момент даже хорошо подобранное хранилище может стать узким местом.
В моей практике разработки часто встречаются сценарии, когда необходимо предоставить доступ к большому количеству данных по HTTP. На первый взгляд задача выглядит простой: берём подходящее хранилище, пишем endpoint, выполняем запрос и отдаём результат пользователю. Но на практике такая схема быстро упирается в ограничения.

Я не люблю Clean Architecture, не люблю DTO и не люблю мапперы.
Они превращают сохранение одной строки в базу в путешествие через четыре проекта, три слоя абстракций и папку Mappings, в которую никто не заглядывал со времён первого коммита. Чтобы добавить одно поле на форму, надо поменять сущность, DTO, команду, валидатор, профиль маппинга и тест на профиль маппинга. Шесть файлов ради одной колонки. А если в одном из них забыть, никто ничего не скажет.
Поэтому я, конечно же, написал маппер.
Если серьёзно, то есть два места, где проблема настоящая. В этой статье я расскажу, что это за места, почему популярные мапперы их нормально не закрывают и что я в итоге с этим сделал.
AI SLOP WARNING. Большую часть кода этой библиотеки написали нейросети, как и 98% текста этой статьи. Я ставил задачи, проверял и исправлял. Если вас это оскорбляет - дальше можно не читать, ничего хорошего вас там не ждёт.

Я написал source generator для лексера HydraScript. Он собирал регулярное выражение из описаний токенов. После этого мне оставалось скопировать регулярку и руками вставить её в другой файл.
Даже тест на забытое копирование пришлось завести. Довольно много усилий, чтобы поддерживать одну строку в актуальном состоянии.
Проблема была в том, что результат моего генератора требовался другому генератору — тому, который стоит за атрибутом [GeneratedRegex] в .NET. Хотелось описать токен один раз и поручить остальное сборке. Для этого пришлось разобраться, в каком порядке Roslyn вообще выполняет генераторы.

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

HydraScript — мой интерпретатор на C#. В нём есть объекты, статическая типизация и вызовы методов. А class, interface и constructor я вообще не добавлял.
Точке на плоскости нужны две координаты, для вычисления расстояния до другой точки нужна функция. Хотелось, чтобы эти вещи работали без обязательной упаковки в класс.
Тут я вдохновлялся сразу двумя языками: структурной типизацией TypeScript и методами с явным получателем из Go. Подход Go заодно сильно упрощал жизнь мне самому — автору языка. Функции у меня уже работали, и методы можно было построить на их основе, не вдаваясь в реализацию классов.

Поле описания merge request пустое или содержит список commit messages. Ревьюер открывает diff на несколько десятков файлов и не понимает, с чего начать. Писать описание руками — рутина, на которую забивают, а задача при этом формализуется идеально: на входе diff, на выходе текст по шаблону. Идеальная работа для LLM.
Так появился AI Describer — CLI‑инструмент, который запускается одним шагом пайплайна, берёт git diff относительно целевой ветки, отдаёт его модели и публикует структурированное описание обратно в merge/pull request. Работает и в GitLab CI, и в Jenkins на Windows‑агентах: у нас два хостинга репозиториев и столько же систем сборки.

В этой статье расскажем, как сделали информационную панель для офиса. Мы написали приложение на Avalonia UI, которое забирает данные из Grafana через REST API и рисует их напрямую, а затем запустили его на старых одноплатных компьютерах — без браузера, рабочего стола и оконного менеджера.

Мне хотелось, чтобы знакомство с HydraScript выглядело просто: скачал интерпретатор, запустил скрипт. Сомнительно предлагать человеку сначала установить подходящий .NET Runtime ради моего языка программирования.
Переход на Native AOT поначалу казался правкой .csproj. Включил настройку, опубликовал бинарник, пошёл дальше. На практике пришлось переписать всё. Досталось даже интеграционным тестам. А в процессе рефакторинга ещё и пропали логи.

Коннектор Redis для redb.Route: все структуры данных как шаги маршрута, Pub/Sub, Streams с группами потребителей, список как очередь и Claim Check на Redis.
В интеграционном проекте Redis редко бывает чем-то одним. Это кэш ответов внешних систем, счётчики и блокировки, шина событий через Pub/Sub, журнал сообщений через Streams, очередь задач на списке. Обычно каждая из этих ролей живёт в своём куске кода со своим подключением, своими повторами и своим логированием.
В redb.Route все они собраны в одном коннекторе redb.Route.Redis. Любая операция Redis становится шагом маршрута, а подписка, стрим или список становятся его входом. Подключение, телеметрия и плавная остановка при этом общие с остальными коннекторами. Под капотом StackExchange.Redis 2.11.8.
Потребители Redis описаны здесь начиная с ...

Мой язык программирования HydraScript, написанный на C#, уже умел выполнять такой код:
let x = 10 x = x + 1 >>> x
Получаем 11; >>> — это оператор вывода. Присваивание работает, сложение работает. Захотелось добавить привычное сокращение:
let x = 10 x += 1 >>> x
Результат должен остаться тем же — 11. Зачем учить весь компилятор ещё одной операции, если всё необходимое у него уже есть? Можно прямо в парсере превратить x += 1 в дерево для x = x + 1.
Эта часть уместилась в несколько строк. Основная работа досталась методу Clone().

Два фронтенда, один C#-мозг — что действительно различается, что похоже сильнее, чем принято считать, и что говорит рынок труда.
До 2019 года моим фронтендом были семантический HTML и CSS. Div'ы, классы, разметка, которую я мог удержать в голове. Я был бэкенд-разработчиком, и меня это вполне устраивало.
Потом случились две вещи. Компания попросила меня залезть в проект на Vue, а Microsoft выпустила Blazor. В следующие годы я плотно поработал с обоими: с Vue — у двух работодателей, с Blazor — на личном проекте, который до сих пор работает.
Это не статья с бенчмарками. Это про то, как эти две технологии ощущаются, когда мышление у тебя C#-овое.

Маршрут в .route.xml на том же движке, что и C#: подсказки в VS Code, проверка пакета в dotnet build, граф-редактор и горячая замена модуля.
Интеграционный маршрут живёт дольше, чем код вокруг него. Партнёр переезжает в другую папку на SFTP, аналитик просит отдельную ветку под новый тип файла, поддержка хочет понять, каким путём прошла заявка, которую ночью отклонили. Всё это вопросы к маршруту, и отвечать на них через C#-проект, сборку и выкладку модуля выходит дороже, чем сам вопрос.
В 4.0 у redb.Route появилась вторая запись маршрута: XML. Файл .route.xml кладётся в пакет, пакет в папку работающего сервиса, и меньше чем через полсекунды по новому маршруту идёт первое сообщение. При этом ...