Arbitrer
Sono un appassionato di programmazione e per vari progetti ho avuto modo di utilizzare uno strumento molto interessante che si chiama MediatR.
MediatR implementa un pattern architetturale molto noto dal nome ... Mediator.
https://dellabate.wordpress.com/2011/12/02/gof-patterns-mediator/
MediatR permette l'invio di messaggi attraverso un intermediario ad un'altro punto dell'applicazione che riceverà il messaggio. Chi invia il messaggio non conosce il punto in cui il messaggio verrà ricevuto, ci pensa l'intermediario a farlo.
Lo scopo di tutto è disaccoppiare il più possibile in modo da rendere le parti completamente indipendenti e legate solo dai messaggi che vendono scambiati.
Fin qui tutto molto bello, peccato che MediatR è in-process! Questo significa che può recapitare il messaggio alle parti dell'applicazione che sono all'interno dello stesso processo. MediatR non può parlare con il mondo esterno.
E qui ci viene in aiuto Arbitrer (lo so il nome può sembrare sbagliato, ma è in francese);
ok potete anche pensare che mi sono sbagliato a tradurre Arbitro in inglese e mi è scappata una "r" di troppo, ma ormai il progetto si chiama Arbitrer, i pacchetti hanno questo nome e cambiare tutto per una "r" è eccessivo.
Quindi ho scelto di tradurre "Arbitro" in francese => Arbitrer.. fatevene una ragione, prima o poi me la farò anche io.
Come funziona Arbitrer
MediatR offre la possibilità di inserirsi nella comunicazione tra il mittente e il ricevente attraverso una interfaccia che si chiama IPipelineBehaviour.
Implementando questa interfaccia MediatR invocherà il nostro "Behaviour" prima di recapitare il messaggio e, tra le altre cose, permette di modificarne il routing.
Arbitrer sfrutta questo meccanismo per instradare il messaggio ad un'altro processo attraverso dei provider che offrono la possibilità di gestire delle code di messaggi più o meno complesse, aspetta che l'altro processo faccia il suo lavoro, e risponde al mittente con la risposta che l'altro processo ha prodotto.
In pratica permette al nostro messaggero di parlare con il mondo esterno. Arbitrer lo aiuta a capire come si fa, e fa il lavoro di consegna.
Chi riceve il messaggio a questo punto deve in qualche modo interpretarlo, gestirlo e rispondere.
Arbitrer è in ascolto di messaggi che il suo processo può gestire, riceve il messaggio, invoca MediatR nel suo processo per quel messaggio e aspetta la risposta per recapitarla indietro.
In un processo MediatR classico gli attori in gioco sono:
Il mittente manda il messaggio all'handler attraverso MediatR, l'handler fa il suo lavoro e ritorna una risposta che MediatR recapita al mittente.
Utilizzando Arbitrer il processo cambia in questo modo:
La comunicazione tra i due processi è affidata ad un provider di arbitrer.
Come cambia il codice di chi sviluppa l'applicazione?
Vediamo un esempio di applicazione con e senza l'utilizzo di Arbitrer.
Codice senza Arbitrer
public class Messaggio:IRequest<Risposta>{}
public class Risposta{}
/* Sender */
...
var risposta = await mediator.Send(new Messaggio());
...
/* Handler */
public class MessageHandler: IRequestHandler<Messaggio,Risposta>
{
public async Task<Risposta> Handler(Messaggio request, CancellationToken cancellationToken)
{
...
return risposta;
}
}
Codice con Arbitrer
public class Messaggio:IRequest<Risposta>{}
public class Risposta{}
/* Sender */
...
var risposta = await mediator.Send(new Messaggio());
...
/* Handler */
public class MessageHandler: IRequestHandler<Messaggio,Risposta>
{
public async Task<Risposta> Handler(Messaggio request, CancellationToken cancellationToken)
{
...
return risposta;
}
}
Vi sembra lo stesso codice ? Lo è!
Arbitrer si inserisce solo a livello di configurazione iniziale. Il resto non comporta nessun cambiamento al modo in cui scriviamo il nostro codice.
Nei prossimi post andremo in dettaglio su come si configura e come si comporta con ogni provider.