Dispatching Requests
Last updated
Was this helpful?
Last updated
Was this helpful?
Once you have , you will want to dispatch Commands or Events to that Handler.
In the following example code we register a handler, create a Command Processor, and then use that Command Processor to dispatch a request to the handler.
In order for the Command Processor to find a Handler for your Command or Event you need to register the association between that Command or Event and your Handler.
Typically, a producer is an ASP.NET WebAPI or MVC app. In this case you take a dependency in your Controller on the IAmACommandProcessor interface, which is satisfied via ServiceCollection.
If you intend to dispatch messages to another app, via message oriented middleware, your Brighter configuration will need a Publication which identifies how to to do that.
An Internal Bus consumer is just a handler, typically registered through Brighter's ServiceCollection integration via our HostBuilder extension. It can thus take dependencies on other registered services within your app.
An External Bus consumer is just a handler, but typically you host it using Brighter's Service Activator. You configure Service Activator to listens to messages flowing over message oriented middleware through a Subscription. Service Activator takes care of listening to messages arriving via the middleware, and delivering them to your handler code. In this way the complexity of using middleware is abstracted away from you, and you can focus on the business logic in your handler that you want to run in response to a message.
Brighter only supports pipelines that are solely IHandleRequestsAsync or IHandleRequests. In particular, note that middleware (attributes on your handler) must be of the same type as the rest of your pipeline. A common mistake is to UsePolicy when you mean UsePolicyAsync.
Once you have registered your Handlers, you can dispatch requests to them.
When using an Internal Bus, the Command Processor has two options for dispatching messages:
Send: Used with a Command, send expects one, and only one, receiver.
Publish: used with an Event, publish expects zero or more receivers.
All methods have versions that support async...await.
A Command is an instruction to do work. We only expect one recipient to do the work, and side-effects mean that we want to ensure that only one receiver actions it as it typically mutates state.
To send a Command you simply use CommandProcessor.Send()
NOTE: On a call to CommandProcessor.Send() the execution path flows to the handler. The Internal Bus is not buffered.
An Event is a fact, often the results of work that has been done. It is not atypical to raise an event to indicate the results of a Command having been actioned.
NOTE: On a call to CommandProcessor.Publish() the execution path flows to all handlers in a loop. The Internal Bus is not buffered.
Post: This is a one-step approach to dispatching a message via middleware. Use it if you do not need transactional messaging, as described above.
All methods have versions that support async...await.
In both cases, if you use an Outbox with external storage, the message will be eventually delivered if it is written to the Outbox, provided that you run an Outbox Sweeper to dispatch any messages in the Outbox that have not been marked as dispatched.
In this example we use CommandProcessor.Post() to dispatch a message over middleware.
In this exaple, we use CommandProcessor.DepositPost() and CommandProcessor.ClearOutbox to raise a transactional message. We then immediately clear it to lower latency. (We could have relied on an Outbox Sweeper and you should have an Outbox Sweeper in case this was to fail).
In this example we are using Dapper as the library for writing our entities to the Db, and have used Brighter's Unit of Work support for that (passed into the handler constructor).
Given you may have both a Command and an Event how do we preserve that behavior (a command expects one handler, an event zero or more) in listening applications?
By setting the Message.MessageType to MT_COMMAND or MT_EVENT you indicate whether you expect this message to be treated as a Command or an Event. We flow that information in the message headers when sending over middleware.
When Service Activator listens to messages it expects that the MessageType matches the type of IRequest, either Command or Event that your message mapper code transforms the message into. It will then use CommandProcessor.Send() to dispatch messages to a single handler, or CommandProcessor.Publish to dispatch messages to zero or more handlers, as appropriate.
Brighter's HostBuilder support provides AutoFromAssemblies to register any Request Handlers in the project. See for more. If you are not using HostBuilder and or ServiceCollection you will need to register your handlers yourself. See .
Brighter follows Command-Query separation, and a Command does not have return value. So CommandDispatcher.Send() does not return anything. Please see a discussion on how to handle this in . Also note that Darker provides our support for a Query over an Internal Bus.
When using an the Command Processor has two options for dispatching a message:
DepositPost and ClearOutbox: This is a two-step approach to dispatching a message via middleware. It allows you to include the DepositPost call that puts the message in your within a database transation, so that you can achieve transactional messaging (either the message is placed in the Outbox and the change is made to any entities, or nothing is written to either).
When sending a message, the is invoked to map your request to a Brighter Message which can be sent over message oriented middleware.