компонуемые .net-блоки для микросервисов
Koto
Koto — это набор небольших NuGet-пакетов, которые аккуратно сшивают Wolverine, Marten, FastEndpoints и EF Core общими правилами игры для DDD, CQRS и event sourcing. Берёте столько, сколько нужно, — остальное спокойно ждёт на полке.
dotnet add package Koto.Domainсмотреть пакеты →как это выглядит ↓
зачем
DDD в .NET — это обычно либо гора boilerplate, либо лицензионная ловушка
Либо вы в каждом сервисе заново пишете always-valid доменные объекты, обработку ошибок через Result и доставку событий через outbox — либо берёте готовый фреймворк и однажды с удивлением узнаёте, что он тихо стал коммерческим (привет, MediatR v13+, MassTransit v9+, FluentAssertions v8+).
Koto — тонкая прослойка поверх бесплатных и лучших в своём классе библиотек: Wolverine для messaging, Marten для event sourcing, FastEndpoints для HTTP, EF Core для хранения. Конвенции — есть. Boilerplate и юридических сюрпризов — нет.
как это выглядит
Доменная модель, которую нельзя собрать в невалидном состоянии
Валидация живёт в фабричном методе, а не размазана по всему проекту. Ошибка — это не исключение, а обычное значение: Result<T>.
объект-значение
public sealed class Email : ValueObject
{
public string Value { get; }
private Email(string value) => Value = value;
public static Result<Email> Create(string value) =>
string.IsNullOrWhiteSpace(value) ? Errors.General.ValueIsRequired() :
value.Length > 150 ? Errors.General.InvalidLength(1, 150) :
new Email(value);
}корень агрегата
public class Order : AggregateRoot<OrderId>
{
public static Result<Order> Place(Customer customer, IReadOnlyList<OrderItem> items)
{
if (items.Count == 0)
return OrderErrors.NoItems();
var order = new Order(OrderId.New(), customer.Id);
order.AddDomainEvent(new OrderPlacedDomainEvent(order.Id, customer.Id));
return order;
}
public Result<Unit> Cancel(string reason)
{
if (Status == OrderStatus.Cancelled)
return OrderErrors.AlreadyCancelled();
Status = OrderStatus.Cancelled;
AddDomainEvent(new OrderCancelledDomainEvent(Id, reason));
return Unit.Value;
}
}как это собирается вместе
Четыре принципа вместо фреймворка
01
Всегда валидный домен
Доменный объект физически нельзя собрать в невалидном состоянии. Вся проверка — в фабричном методе, а не в отдельных валидаторах где-то сбоку.
02
Явные ошибки, от начала до конца
Никаких исключений на ожидаемые сбои. Result<T> едет от домена до самого HTTP-ответа, не теряясь по дороге.
03
События сами долетают до Kafka
Доменное событие попадает в outbox в той же транзакции, что и запись. Дальше — почти автомагически: Wolverine его достаёт, in-process хендлер публикует интеграционное событие, а Kafka разносит по остальным сервисам.
04
Без магии
Никакой рефлексии на горячем пути и скрытых конвенций, которые выстрелят в два часа ночи. Код, который вы написали, — ровно тот код, что выполняется.
доменное событие → Kafka, автоматически
Order.Cancel()
→ AddDomainEvent(OrderCancelledDomainEvent)
→ DbContext.SaveChangesAsync() // outbox, same transaction
→ Wolverine delivers to in-process handler
→ handler publishes OrderCancelledIntegrationEvent
→ Kafka → other servicesпакеты
Четырнадцать пакетов. Берите нужные — остальные не мешают.
Koto.Domain
DDD-примитивы для .NET-микросервисов. Ноль внешних зависимостей.
Koto.Application
CQRS-диспетчер, pipeline-поведения и абстракции межсервисной интеграции.
Koto.Validation
Расширения FluentValidation и pipeline-поведение для CQRS.
Koto.Infrastructure.EFCore
Интеграция с EF Core 10: универсальный репозиторий, типобезопасные ID, спецификации и outbox через Wolverine.
Koto.Infrastructure.Http
Anti-Corruption Layer для синхронных HTTP-вызовов между сервисами.
Koto.EventSourcing.Marten
Event sourcing на PostgreSQL через Marten.
Koto.Messaging.Wolverine
Messaging-абстракции Koto поверх Wolverine и Kafka.
Koto.Messaging.Wolverine.Postgres
Надёжное хранилище идемпотентности на PostgreSQL — дедупликация переживает перезапуски.
Koto.Api.AspNetCore
Транспорт-независимая интеграция с ASP.NET Core — Minimal API, MVC или любой хост.
Koto.Api.FastEndpoints
Интеграция FastEndpoints с DDD-примитивами Koto.
Koto.Observability
Observability одной строкой: Serilog и OpenTelemetry.
Koto.Scheduling
Плановые задачи и пакетная обработка на Quartz.NET.
Koto.Testing
Тестовые хелперы под DDD: Given/When/Then для агрегатов.
Koto.Testing.Integration
Кирпичики для интеграционных тестов: тестовая авторизация через заголовок, проверки Eventually и продюсер raw-JSON в Kafka.
начало работы
Добавьте пакеты, которые нужны
dotnet add package Koto.Domain
dotnet add package Koto.Application
dotnet add package Koto.Infrastructure.EFCoreлицензия mit · опубликовано на nuget
Сделано для настоящего продакшена — и открыто для всех остальных
Koto вырос из живого .NET-бэкенда на микросервисах и переехал в отдельный репозиторий тогда, когда абстракции наконец отработали свой хлеб.