Behaviors
The behaviors can be used to build a custom pipeline (similar to the asp.net pipeline), easily adding your cross-cutting concerns such as logging, validation, etc.
The behaviors are implementations of the IBehavior interface and will be invoked by the IPublisher every time a message is published to the internal bus (this includes the inbound/outbound messages, but they will be wrapped into an IInboundEnvelope<TMessage> or IOutboundEnvelope<TMessage>).
The HandleAsync method of each registered behavior is called every time a message (or a batch of messages) is published to the internal bus, passing in the collection of messages and the delegate to the next step in the pipeline. This gives you the flexibility to execute any sort of code before and after the messages have been actually published (before or after calling the next
step). You can for example modify the messages before publishing them, validate them (like in the above example), add some logging / tracing, etc.
The IBehavior implementation have simply to be registered for DI.
IBehavior example
The following example demonstrates how to use a behavior to trace the messages.
public class TracingBehavior : IBehavior
{
private readonly ITracer _tracer;
public TracingBehavior(ITracer tracer)
{
_tracer = tracer;
}
public async Task<IReadOnlyCollection<object?>> HandleAsync(
object message,
MessageHandler next)
{
tracer.TraceProcessing(message);
var result = await next(message);
tracer.TraceProcessed(message);
return result;
}
}
Note
IInboundEnvelope and IOutboundEnvelope are internally used by Silverback to wrap the messages being sent to or received from the message broker and will be received by the IBroker. Those interfaces contains the message plus the additional data like endpoint, headers, offset, etc.
Sorting
The order in which the behaviors are executed might matter and it is possible to precisely define it implementing the ISorted interface.
public class SortedBehavior : IBehavior, ISorted
{
public int SortIndex => 120;
public Task<IReadOnlyCollection<object?>> HandleAsync(
object message,
MessageHandler next)
{
// ...your logic...
return next(message);
}
}