MediatR publish and MediatR send

Tonto picture Tonto · Jul 31, 2020 · Viewed 7k times · Source

I have tried the CQRS pattern using MediatR and am loving the clean state in which applications am working on are transforming. In all the examples i have seen and used, I always do

await Mediator.Send(command);

It's been same for the queries as well

var data = await Mediator.Send(queryObject);

I just realized there's Mediator.Publish as well which after searching seems to me to be doing the same thing. I am trying to understand what the difference between the Mediator.Send and Mediator.Publish is. I have read the MediatR library docs and I still don't understand what the difference between these are. Kindly help me understand the difference.

Thanks for your help

Answer

zolty13 picture zolty13 · Jul 31, 2020

MediatR has two kinds of messages it dispatches:

  • Request/response messages, dispatched to a single handler
  • Notification messages, dispatched to multiple handlers
  • Send may return a response, but do not have to do it.
  • Publish never return the result.

You are sending requests (sometimes called commands) by _mediator.Send({command}) to exactly one concrete handler. It may be e.g. command that saves a new product to the database. It is often a request from the user (frontend/API) or sometimes it may be internal command in your system given by other service in a synchronous way. It is always expected that the command will be executed immediately and you will receive some proper result or error to immediately inform the client about some failures.

You are publishing notifications (often called events) by _mediator.Publish({event}) to zero, one or many handlers. You used notifications when you want to publish some information and you do not know who needs that. E.g. NewProductEvent which is published after successfully adding product to your Warehouse Module. Few other contexts want to subscribe the information and e.g. send email to a client that a new product is available or create some default configuration for the product in your Store Module (which payment and delivery are available for the product). You may use notifications in a synchronous way. All data will be saved in one transaction (product and store configuration) or you may use some async pattern with service bus or/and sagas. In the second case (asynchronous) you must manually handle cases when something wrong happens in other services or contexts which subscribe to your notification.

Example scenario: Default configuration was not created.

  • If you have one transaction (synchronous way) for a few contexts, you will receive an error, log the error and return it to the user/client.
  • In an asynchronous way, you send events after saving a new product to the database. You do not want to have the product in a half-error state in your system. So firstly I recommend creating it in the Draft state and wait for an event that informs you about the successfully created configuration and then changes the state to e.g New/Correct etc.

A good example of using mediatR you will find in e.g. Ordering microservice in EShopOnContainers by Microsoft: github. You will see an example usage of CQRS and DDD with EF core and ASP Net.