From b36a3e400a9030525c323414b1b288a855033825 Mon Sep 17 00:00:00 2001 From: Mark van Renswoude Date: Fri, 29 Oct 2021 21:07:51 +0200 Subject: [PATCH] Added documentation for #37 --- docs/flow.rst | 3 +++ docs/gettingstarted.rst | 5 ++++- docs/indepth.rst | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/docs/flow.rst b/docs/flow.rst index 25cd90f..53bcabb 100644 --- a/docs/flow.rst +++ b/docs/flow.rst @@ -289,3 +289,6 @@ Then install the Tapeti.Flow.SQL NuGet package and register the SqlConnectionFlo .WithFlow() .RegisterAllControllers() .Build(); + + +.. caution:: The controller and method names for response handlers and converge methods are stored in the flow and must be valid when they are loaded again. Keep that in mind if you want to refactor the code; either keep the original class and method temporarily for backwards compatibility, optionally redirecting them internally to the new code, or make sure there are no persisted flows remaining. \ No newline at end of file diff --git a/docs/gettingstarted.rst b/docs/gettingstarted.rst index a4826c7..e011a2c 100644 --- a/docs/gettingstarted.rst +++ b/docs/gettingstarted.rst @@ -102,7 +102,10 @@ Any public method in a message controller is considered a message handler. There - The first parameter must be the message class. - The return type can be void, Task, Task or a message class. -The name of the method is not important to Tapeti. Any parameter other than the first will be resolved using the IoC container, although it is considered best practice to use the constructor for dependency injection instead. +The name of the method is not important to Tapeti. Any parameter other than the first will be resolved in two ways: + +1. Registered middleware can alter the behaviour of parameters. Tapeti includes one by default for CancellationToken parameters, see :ref:`parameterbinding` in :doc:`indepth`. +2. Any remaining parameters are resolved using the IoC container, although it is considered best practice to use the constructor for dependency injection instead. A new controller is instantiated for each message, so it is safe to use public or private fields to store state while handling the message. Just don't expect it to be there for the next message. If you need this behaviour, take a look at the :doc:`flow`! diff --git a/docs/indepth.rst b/docs/indepth.rst index c4e4fe6..8b68d6b 100644 --- a/docs/indepth.rst +++ b/docs/indepth.rst @@ -9,6 +9,46 @@ As described in the Getting started guide, a message is a plain object which can When communicating between services it is considered best practice to define messages in separate class library assemblies which can be referenced in other services. This establishes a public interface between services and components without binding to the implementation. +.. _parameterbinding: + +Parameter binding +----------------- +Tapeti will bind the parameters of message handler methods using the registered binding middleware. + +Although stated in the Getting started guide that the first parameter is always assumed to be the message class, this is in fact handled by one of the default binding middleware implementations instead of being hardcoded in Tapeti. All of the default implementations play nice and will only apply to parameters not already bound by other middleware, making it easy to extend or change the default behaviour if desired. + +In addition to the message class parameter, two additional default implementations are included: + + +CancellationToken +^^^^^^^^^^^^^^^^^ +Similar to ASP.NET, Tapeti will bind parameters of type CancellationToken to a token which is cancelled when the connection to the RabbitMQ server is closed. + +.. note:: This does not indicate whether the connection was closed by the application or lost unexpectedly, either scenario will cancel the token. This is by design, as any message in-flight will be put back on the queue and redelivered anyways. + +Internally this CancellationToken is called ConnectionClosed, but any name can be used. For example: + +:: + + public async Task CountRabbits(CountRequestMessage message, + CancellationToken cancellationToken) + { + var count = await rabbitRepository.Count(cancellationToken); + + return new CountRabbitsResponseMessage + { + Count = count + }; + } + + +Dependency injection +^^^^^^^^^^^^^^^^^^^^ +Any parameter not bound by any other means will be resolved using the IoC container which is passed to the TapetiConnection. + +.. note:: It is considered best practice to use the constructor for dependency injection instead. + + Enums ----- Special care must be taken when using enums in messages. For example, you have several services consuming a message containing an enum field. Some services will have logic which depends on a specific value, others will not use that specific field at all. @@ -82,6 +122,7 @@ If all message handlers bound to a durable queue are marked as obsolete, includi If there are still messages in the queue it's pending removal will be logged but the consumers will run as normal to empty the queue. The queue will then remain until it is checked again when the application is restarted. + Request - response ------------------ Messages can be annotated with the Request attribute to indicate that they require a response. For example: