Migrating from v4 to v5
Silverback 5 is a complete refactoring of the library. Most concepts (message bus, subscribers, behaviors, producers and consumers, error policies, outbox) are still there, but the configuration API, the storage layer and several interfaces changed. This guide walks you through the most common steps to upgrade an existing v4 application.
Tip
The release notes contain the complete list of the new features and breaking changes.
1. Target .NET 10 and Update the Packages
Starting with v5, Silverback targets only the latest .NET LTS release (currently .NET 10).
- Update your projects to
net10.0. - Upgrade all
Silverback.*packages to the same 5.x version. - The RabbitMQ integration has been discontinued: Silverback.Integration.RabbitMQ is not available for v5.
- The storage-dependent features moved to the new storage packages: Silverback.Storage.EntityFramework, Silverback.Storage.PostgreSql, Silverback.Storage.Sqlite and Silverback.Storage.Memory (see Storage Integration).
Some extension methods moved to different namespaces, so a few using directives need to be adjusted (e.g. Silverback.Messaging.Configuration → Silverback.Configuration).
2. Migrate the Endpoints Configuration
The biggest change is the configuration of the broker endpoints. AddKafkaEndpoints/AddMqttEndpoints with AddOutbound/AddInbound have been replaced by AddKafkaClients/AddMqttClients, where you configure the clients (producers and consumers) and their typed endpoints using Produce<TMessage> and Consume<TMessage>. The Confluent and MQTTnet settings are now exposed as fluent configuration methods instead of the Configure callback.
services.AddSilverback()
.WithConnectionToMessageBroker(options => options.AddKafka())
.AddKafkaEndpoints(endpoints => endpoints
.Configure(config =>
{
config.BootstrapServers = "PLAINTEXT://localhost:9092";
})
.AddOutbound<OrderCreatedEvent>(endpoint => endpoint
.ProduceTo("order-events"))
.AddInbound(endpoint => endpoint
.ConsumeFrom("inventory-events")
.Configure(config =>
{
config.GroupId = "my-consumer";
config.AutoOffsetReset = AutoOffsetResetType.Earliest;
})
.OnError(policy => policy.Retry(3).ThenSkip())));
Things to keep in mind:
- In Kafka, each
AddProducer/AddConsumercreates a dedicated client. Group multiple endpoints in the same client to reduce the number of connections. With MQTT, a single client (AddClient) can both produce and consume. - The message type passed to
Consume<TMessage>is used to select the default deserializer, so thex-message-typeheader is not needed anymore for non-polymorphic topics (see Deserializing the Consumed Messages). - Some settings moved from the endpoint to the consumer, such as the parallelism (
LimitParallelism,ProcessAllPartitionsTogether,LimitBackpressure). IEndpointsConfiguratorhas been replaced by IBrokerClientsConfigurator, registered viaAddBrokerClientsConfigurator.- Assigning a name to the clients and endpoints (e.g.
AddProducer("producer1", ...),Produce<T>("endpoint1", ...)) is optional but recommended, and required when using the outbox.
See Connecting to a Message Broker, Producing Messages and Consuming Messages for the details.
3. Replace the Specialized Publishers
IEventPublisher, ICommandPublisher and IQueryPublisher have been removed (as well as the UseModel configuration method). Use the equivalent extension methods on IPublisher (from the Silverback.Core.Model package) or inject the IApplicationPublisher if you prefer a more easily mockable interface.
public class OrderService
{
private readonly IEventPublisher _publisher;
public OrderService(IEventPublisher publisher) => _publisher = publisher;
public Task PlaceOrderAsync(Order order) =>
_publisher.PublishAsync(new OrderCreatedEvent(order.Id));
}
The IPublisher is now registered as transient and can be injected into singleton services. All publishing methods accept a CancellationToken.
4. Review the Behaviors and Callbacks
- IBehavior, IProducerBehavior and IConsumerBehavior now return
ValueTaskand receive aCancellationToken(see Using the Message Bus, Producer Behaviors Pipeline and Consumer Behaviors Pipeline). IBrokerCallbackand theAdd*BrokerCallbackHandlermethods have been renamed toIBrokerClientCallbackandAdd*BrokerClientCallback(see Broker Callbacks).IBrokerandIBrokerCollectionhave been removed. UseIProducerCollection,IConsumerCollectionand IBrokerClientCollection instead (see Connecting to a Message Broker).- The
IMessageSerializerinterface has been split into IMessageSerializer and IMessageDeserializer.
5. Migrate the Outbox and the Storage
The outbox and all storage-backed features have been rewritten from scratch.
- Reference the storage package matching your database and configure the outbox and the outbox worker as shown in Transactional Outbox.
- With Entity Framework, add the
SilverbackOutboxMessage(and, if used, theSilverbackLock) entities to yourDbContextand create a migration. The table schema differs from v4. - Writing to the outbox is not automatically part of your database transaction anymore: begin the transaction explicitly and enlist it in the publisher (
EnlistDbTransaction) to keep the application changes and the outbox messages atomic. - The exactly-once guard (inbound log / offset store) has been replaced by the client-side offset storage (see Kafka Offset Storage).
Important
Make sure the v4 outbox is empty before switching to v5, since the messages stored by v4 cannot be processed by the new outbox worker.
6. Check the Changed Defaults
A few defaults changed and might affect the behavior of your application:
- The Kafka key isn't set to a random
Guidanymore but isnullunless explicitly set (see Kafka Keys and Partitioning). - The JSON deserializers don't use the
x-message-typeheader by default. Enable it explicitly if you rely on polymorphic deserialization (see Deserializing the Consumed Messages). - The Newtonsoft.Json serializer uses
TypeNameHandling.Noneand the Newtonsoft.Json default value handling. - The Kafka consumer processes up to 100 partitions in parallel (
MaxDegreeOfParallelism) and buffers up to 50 messages per partition (BackpressureLimit). - The MQTT producer doesn't throw anymore if no subscriber is consuming the produced message.
7. Update the Tests
The testing helpers (ITestingHelper, IKafkaTestingHelper and IMqttTestingHelper) changed in a few places, and new envelope builders are available to create test envelopes. See Testing.