From 6c8c8b702902d229240c5aab8afaa3a9edc3a98a Mon Sep 17 00:00:00 2001 From: BEagle1984 Date: Tue, 31 Dec 2019 17:25:04 +0100 Subject: [PATCH] Documented release 1.1.0 --- Directory.Build.props | 2 +- docs/_docs/0-introduction/003-releases.md | 2 +- docs/_docs/1-quickstart/107-behaviors.md | 125 +++++++++++++--------- 3 files changed, 79 insertions(+), 50 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index b29d24a3f..5c3ddd222 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,7 +5,7 @@ Silverback is a simple framework to build reactive, event-driven, microservices. MIT Copyright (c) 2019 Sergio Aquilini - -rc3 + 1.1.0$(VersionSuffix) https://beagle1984.github.io/silverback/ https://github.com/BEagle1984/silverback/ diff --git a/docs/_docs/0-introduction/003-releases.md b/docs/_docs/0-introduction/003-releases.md index 544cb820b..db68e6c9d 100644 --- a/docs/_docs/0-introduction/003-releases.md +++ b/docs/_docs/0-introduction/003-releases.md @@ -4,7 +4,7 @@ permalink: /docs/releases toc: true --- -## [1.1.0-rc3](https://github.com/BEagle1984/silverback/releases/tag/1.1.0-rc3) +## [1.1.0](https://github.com/BEagle1984/silverback/releases/tag/1.1.0) ### What's new * Added `IEndpointsConfigurator` interface to allow splitting the endpoints configuration across multiple types (see [Connecting to a Message Broker]({{ site.baseurl }}/docs/quickstart/message-broker#using-iendpointsconfigurator)) diff --git a/docs/_docs/1-quickstart/107-behaviors.md b/docs/_docs/1-quickstart/107-behaviors.md index 5cec3815d..606d39357 100644 --- a/docs/_docs/1-quickstart/107-behaviors.md +++ b/docs/_docs/1-quickstart/107-behaviors.md @@ -1,69 +1,106 @@ --- title: Behaviors permalink: /docs/quickstart/behaviors -toc: false +toc: true --- The behaviors can be used to build a custom pipeline (similar to the asp.net pipeline), easily adding your cross-cutting functionalities such as logging, validation, etc. ## IBehavior -A behavior must implement the `IBehavior` interface and be registered for dependency injection. +The behaviors implementing the `IBehavior` interface will be invoked by the `IPublisher` internals every time a message is published to the internal bus (this includes the wrapped `IInboundMessage` and `IOutboundMessages` that are generated to produce or consume a message from the message broker). + +At every call to `IPublisher.Publish` the `Handle` method of each registered behavior is called, 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. + +### IBehavior example + +The following example demonstrates how to use a behavior to trace the messages. ```c# using Silverback.Messaging.Publishing; -public class ValidationBehavior : IBehavior +public class TracingBehavior : IBehavior { + private readonly ITracer _tracer; + + public TracingBehavior(ITracer tracer) + { + _tracer = tracer; + } + public async Task> Handle( IEnumerable messages, MessagesHandler next) { - foreach (var validatedMessage in messages.OfType(IValidatedMessage)) - { - if (!validatedMessage.IsValid()) - { - throw new InvalidMessageException(); - } - } + tracer.TraceProcessing(messages); + var result = await next(messages); + tracer.TraceProcessed(messages); - return await next(messages); + return result; } } ``` + +**Note:** The `Handle` receives a collection of `object` because a bunch of messages can be published at once via `IPublisher` or the consumer can be configured to process the messages in batch. +{: .notice--info} + +**Note:** `IInboundMessage` and `IOutboundMessage` 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. +{: .notice--info} + +The `IBehavior` implementation have simply to be registered for DI. + ```c# public void ConfigureServices(IServiceCollection services) { services .AddSilverback() - .AddScopedBehavior(); + .AddScopedBehavior(); ``` **Note:** All `Add*Behavior` methods are available also as extensions to the `IServiceCollection` and it isn't therefore mandatory to call them immediately after `AddSilverback`. {: .notice--info} -At every call to `IPublisher.Publish` the `Handle` method of each registered behavior is called, passing in the array 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. +## IProducerBehavior and IConsumerBehavior + +The `IProducerBehavior` and `IConsumerBehavior` are similar to the `IBehavior` but work at a lower level, much closer to the message broker. -### Example1: Modifying outbound message headers +### IProducerBehavior example -The behaviors can be quite useful to get and set the message headers for inbound/outbound messages. +The following example demonstrate how to set a custom message header on each outbound message. ```c# -public class CustomHeadersBehavior : IBehavior +public class CustomHeadersBehavior : IProducerBehavior { - public async Task> Handle( - IEnumerable messages, - MessagesHandler next) + public async Task Handle(RawBrokerMessage message, RawBrokerMessageHandler next) + { + message.Headers.Add("generated-by", "silverback"); + } +} +``` + +### IConsumerBehavior example + +The following example demonstrate how to log the headers received with each inbound message. + +```c# +public class LogHeadersBehavior :IConsumerBehavior +{ + private readonly ILogger _logger; + + public LogHeadersBehavior(ILogger logger) + { + _logger = logger; + } + + public async Task Handle(RawBrokerMessage message, RawBrokerMessageHandler next) { - foreach (var message in messages.OfType()) + foreach (var header in message.Headers) { - message.Headers.Add( - "generated-by", - "silverback"); - message.Headers.Add( - "timestamp", - DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")); + _logger.LogTrace( + "{key}={value}", + header.Key, + header.Value); } return await next(messages); @@ -71,16 +108,18 @@ public class CustomHeadersBehavior : IBehavior } ``` -### Example2: Logging inbound message headers +### Limitations + +Because of the way the Silverback's broker integration works `IProducerBehavior` and `IConsumerBehavior` implementations can only be registered as singleton. If a scoped instance is needed you have to either reference the `IServiceProvider` or use an `IBehavior` (that can still be used to accomplish most of the tasks, as shown in the next example). ```c# -public class LogHeadersBehavior : IBehavior +public class TracingBehavior : IBehavior { - private readonly ILogger _logger; + private readonly IDbLogger _dbLogger; - public LogHeadersBehavior(ILogger logger) + public TracingBehavior(IDbLogger _dbLogger) { - _logger = logger; + _dbLogger = dbLogger; } public async Task> Handle( @@ -89,26 +128,16 @@ public class LogHeadersBehavior : IBehavior { foreach (var message in messages.OfType()) { - if (message.Headers != null && message.Headers.Any()) - { - _logger.LogInformation( - "Headers: {headers}", - string.Join(", ", - message.Headers.Select(h => $"{h.Key}={h.Value}"))); - } + _dbLogger.LogInboundMessage( + message.Content.GetType(), + message.Headers, + message.Endpoint, + message.Offset); } + await _dbLogger.SaveChangesAsync(); + return await next(messages); } } ``` - -**Note:** `IInboundMessage` and `IOutboundMessage` are internally used by Silverback to wrap the messages being sent to or received from the message broker. -{: .notice--info} - -## IProducerBehavior and IConsumerBehavior - -The `IProducerBehavior` and `IConsumerBehavior` are similar to the `IBehavior` but work at a lower level, much closer to the message broker. You should be able to accomplish most tasks with the normal `IBehavior`. - -**Note:** Because of the way the Silverback's broker integration works `IProducerBehavior` and `IConsumerBehavior` implementations can only be registered as singleton. -{: .notice--info} \ No newline at end of file