The Jerusalem PostXi's visit to Egypt marks Chinese interest in Middle East, Egypt's push to keep growing - analysisRTP DesportoAvançado Malik Abubakari regressa a Portugal para reforçar o TorreenseEl ComercioTrump y el petróleo de Venezuela: ¿qué significa el “histórico” acuerdo que da a EE.UU. acceso a 65.000 millones de barriles?וואלהדיווחים פלסטיניים: כוח מיוחד של צה"ל נחשף ברצועת עזה, חילופי אש במקוםDaily MaverickAfter student’s shooting rampage, Thai school reopens under tight securityInquirer EntertainmentBINI to headline Asia Pop Girl Fest 2027 with HANA, 4EVEBollywood HungamaSaif Ali Khan vs Akshay Kumar: Haiwaan makers unveil unique audio promo ahead of releaseInquirerMindoro solon seeks to fast-track Victoria-Sablayan road projectBBC NewsAston Villa complete £47m Mbaye signingVanguardEkiti 2027: APC, ADC, 10 other parties set for battle over 26 Assembly seatsIl Fatto QuotidianoIlva, l’ultima carta contro la chiusura dell’area a caldo: il 9 settembre l’udienza per la sospensione del decretoBBC SportEvery done deal on transfer deadline day
The Daily Newsstand · Free, Always
Tuesday, September 1, 2026

redb.Route 4.0: тест-кит, шаблоны payload, форматы данных, REST DSL и ядро без Newtonsoft

Translate

Восемь новых пакетов и REST DSL вокруг прежних 56 глаголов маршрута; из ядра ушёл Newtonsoft.Json. Что ломает мажор и как мигрировать за десять минут.

Готовится четвёртая версия redb.Route, интеграционного движка для .NET в духе Apache Camel. В 3.x была закрыта ширина по паттернам: 56 глаголов DSL, тридцать с лишним коннекторов, свой язык выражений, скомпилированный в IL (в 4.0 он качественно переработан, об этом ниже). 4.0 закрывает то, что вокруг паттернов: как протестировать маршрут без брокеров, как собрать тело сообщения, как читать CSV и Avro, как выставить REST-фасад, как кэшировать ответ сервиса. Восемь новых пакетов, REST DSL внутри HTTP-коннектора, переработанный язык выражений и ядро, которое стало легче, а не тяжелее. За год это первый мажор такого масштаба: не смена номера под несколько ломающих правок, а качественное расширение функционала, и ломающих изменений в нём как раз немного.

Что появилось

  • redb.Route.TestKit. Маршрут без брокеров и без правок в нём: AdviceRoute с ReplaceFromMockEndpoints("kafka://*")WeaveById; богатый MockEndpoint с ожиданиями и сценарными ответами; NotifyBuilderctx.SendBody вместо связки эндпоинт/продюсер. Без зависимости на тестовый фреймворк.

  • redb.Route.Templates. Тело из шаблона на Scriban: SetBodyTemplate("order.json.sbn", MediaType.Json, args). Тип результата обязателен и задаёт экранирование подставленных значений, шаблон компилируется при Start(), песочница без вызова методов, режим Liquid.

  • redb.Route.DataFormats.Csv / Protobuf / Avro / Yaml плюс Base64, GZip и Zip в ядре. Каждый формат это IMessageSerializer, так что Marshal("text/csv")UnmarshalCsv<List<Row>>() и разбор по ContentType сообщения работают через уже существующие узлы. У Protobuf и Avro есть обрамление Confluent.

  • redb.Route.JsonTransform. JSON в JSON на JSONata с нативным .NET-движком: TransformJson("order-to-shipment.jsonata"), в спецификации доступны $headers и $properties.

  • redb.Route.Cache. Кэш как EIP в двух формах над одним хранилищем: скоуп Cache(key, ttl)…EndCache() и компонент cache:region?action=get|put|remove|clear. В процессе через IMemoryCache, распределённо через любой IDistributedCache.

  • REST DSL в redb.Route.Http. Rest("/api/orders").Get("/{id}").OutType<Order>().To(...)Consumes / Produces с 415, JSON-биндинг, OpenAPI 3.0.3 по адресу {basePath}/openapi.json. Поверх существующего консюмера и общего Kestrel-хоста.

  • В ядре: AggregationStrategies (одиннадцать готовых стратегий для AggregateMulticastSplitEnrich), Enrich без стратегии, keyed throttle с лимитом из сообщения, Intercept / InterceptFrom / InterceptSendToEndpoint с сухим прогоном, OnCompletionSetHeadersRemoveHeaders(маска)Sort.

Пример из первого пункта, потому что с него обычно начинается знакомство:

await using var ctx = new RouteContext().AddRoutes(new OrdersRoutes());

ctx.AdviceRoute("orders", a => a
    .ReplaceFrom("direct://test-in")            // вместо kafka://orders
    .MockEndpoints("kafka://*", "sql:*"));      // каждый подходящий To(...) уходит в мок

await ctx.Start();

var vip = ctx.Mock("kafka://orders-vip").ExpectMessageCount(1).ExpectHeader("priority", "high");
await ctx.SendBodyAndHeader("direct://test-in", order, "priority", "high");
await vip.AssertIsSatisfiedAsync(TimeSpan.FromSeconds(2));

Кто писал такое на Camel, узнает adviceWithmockEndpoints и mock:kafka:orders-vip. Это намеренно: там, где форма Camel верна, взяты и форма, и имена. Где разошлись, разобрано в полной статье.

Ядро стало легче

Из зависимостей redb.Route ушёл Newtonsoft.Json: jpath переехал на JsonPath.Net (RFC 9535) поверх System.Text.Json, и в ядре осталась одна JSON-модель на сериализатор, валидацию по схеме, jpath и форматы. Перед заменой диалект был снят снимком на 60 форм; 44 совпали байт в байт, 16 расхождений перечислены в changelog. Ни Scriban, ни CsvHelper, ни Google.Protobuf, ни Chr.Avro, ни YamlDotNet, ни Jsonata, ни абстракции кэширования в ядро не попали, каждая библиотека живёт в своём пакете.

Язык выражений

В 4.0 входит и переработанный язык выражений: одна грамматика и один компилятор для условий, значений и ${...}-шаблонов вместо трёх движков с несовпадающими дырами. Условие читается независимо от пробелов (header.amount>1000 больше не отбрасывает молча весь поток), битое условие или плейсхолдер роняют Start(), а не превращаются в константу на живом трафике, предикаты ждутся асинхронно, Validate и LoopWhile принимают строку. Второй, рукописный разборщик логики удалён целиком, около 800 строк. Поведение при этом меняется в трёх местах: одно правило истинности везде (ноль, "0""no" и "off" теперь ложь), плейсхолдер на всю строку ${header.a} сохраняет CLR-тип значения, отсутствующее значение через Evaluate<string> даёт null, а не пустую строку. Всё закреплено сеткой характеризации на две с лишним сотни форм в трёх позициях. Разбор языка целиком выйдет отдельной статьёй вслед за релизом.

Что ломает мажор

Список короткий; кроме правила истинности, вся миграция механическая.

Было

Стало

LoopExpression("${header.count}")

Loop("${header.count}")

DelayExpression("${header.backoff}")

Delay("${header.backoff}")

ThrottleExpression("${header.rate}", period)

Throttle("${header.rate}", period)

${header.price} давал 2,5 на сервере с ru-RU

2.5 на любой машине; даты в ISO 8601

From("kafka://orders-${header.region}") молча оставался текстом

ошибка при Start(); нужны {{key}} или константа

jpath на Newtonsoft: дата в JSON становилась DateTime, число в строке по культуре, JObject в object

строка остаётся строкой, числа инвариантно, JsonObject, RFC 9535

Filter("${header.zero}") пропускал сообщение с нулём, строки "0" и "no" были истиной

одно правило истинности: ноль и слова-отрицания ложь

Expr("${header.a}") с целым заголовком давал строку "10"

плейсхолдер на всю строку отдаёт intEvaluate<string> по-прежнему конвертирует

Перегрузки LoopExpression(IExpression, …)DelayExpression(IExpression) и ThrottleExpression(IExpression, period) остались: суффикс Expression во всём DSL означает «принимает IExpression», а строку принимает сам глагол, как Filter(string) принимал всегда. Пакеты, получавшие Newtonsoft транзитивно через redb.Route, добавляют собственную ссылку.

Как это будет ставиться

dotnet add package redb.Route
dotnet add package redb.Route.TestKit
dotnet add package redb.Route.Templates
dotnet add package redb.Route.DataFormats.Csv      # Protobuf / Avro / Yaml по той же схеме
dotnet add package redb.Route.JsonTransform
dotnet add package redb.Route.Cache
dotnet add package redb.Route.Http                 # REST DSL внутри

Пакеты выйдут одной линией 4.0.0, 45 штук на одном номере, под net8.0net9.0 и net10.0. Бесплатно, как и ядро. Полный разбор с примерами по каждому пакету, устройством под капотом и сравнением с Camel выйдет вместе с релизом, следом за ним отдельная статья про язык выражений. Исходники на github.com/redbase-app, пакеты на NuGet.

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.