Recientemente escribí una publicación de blog que presenta algunos de mis paquetes NuGet favoritos: Mis 4 paquetes NuGet principales para ASP.NET Core . En esa publicación, presenté brevemente un paquete llamado MediatR. Hoy, dedicaré esta publicación a revisar MediatR con más detalle.
MediatR es una implementación del patrón mediador. Es un patrón de diseño de software de comportamiento que lo ayuda a crear un código más simple al hacer que todos los componentes se comuniquen a través de un objeto "mediador", en lugar de hacerlo directamente entre sí. Esto ayuda a que el código permanezca altamente desacoplado y reduce la cantidad de dependencias complejas entre objetos.
Un buen ejemplo del mundo real del patrón mediador es la torre de control de tráfico aéreo (ATC) en los aeropuertos. Si cada plano tuviera que comunicarse directamente con todos los demás planos, sería un caos. En cambio, todos informan a la torre ATC, y la torre decide cómo transmitir esos mensajes a otras aeronaves. En este escenario, la torre ATC es el objeto mediador.
Usando el paquete MediatR, uno envía algunos datos como un objeto al objeto mediador. Según el tipo de datos que se envían al objeto mediador, decide a qué otros objetos/servicios llamar. MediatR maneja dos formas de mensaje:
Para obtener MediatR, instale el paquete MediatR de NuGet. Si está utilizando ASP NET Core, también debe instalar MediatR.Extensions.Microsoft.DependencyInjection, que proporciona una manera fácil de registrar todos los servicios de MediaR:
// Startup.cs public void ConfigureServices ( IServiceCollection services ) { // other services services.AddMediatR( typeof (Startup)); }
Si está utilizando un método diferente de inyección de dependencia, consulte la wiki sobre cómo configurar MediatR para su contenedor.
Para enviar una solicitud, debe crear dos objetos: una solicitud y un controlador de solicitudes.
El objeto de solicitud debe implementar las interfaces IRequest o IRequest<TResponse>, dependiendo de si desea o no devolver datos. El objeto de solicitud debe consistir en cualquier dato que desee enviar al controlador.
public class AdditionRequest : IRequest < int > { public int A { get ; set ; } public int B { get ; set ; } }
El controlador de solicitudes debe implementar las interfaces IRequestHandler<TRequest> o IRequestHandler<TRequest, TResponse>, donde TRequest es el objeto de solicitud que acaba de crear.
public class AdditionRequestHandler : IRequestHandler < AdditionRequest , int > { public Task< int > Handle ( AdditionRequest request, CancellationToken cancellationToken ) { var result = request.A + request.B; return Task.FromResult(result); } }
Para luego enviar la solicitud a través de MediatR, se debe usar el método Send en la instancia de IMediator, pasando una instancia de AdditionRequest.
public class MyCalculator { private readonly IMediator _mediator; public MyCalculator ( IMediator mediator ) { _mediator = mediator; } public async Task< int > Add ( int a, int b ) { var request = new AdditionRequest { A = a, B = b }; var result = await _mediator.Send(request); return result; } }
Tenga en cuenta que si elige no devolver nada de un controlador de solicitudes, MediatR en realidad tiene un valor especial de "nada" que debe devolver en su lugar, llamado Unidad.
public class MyRequest : IRequest { // some properties } public class MyRequestHandler : IRequestHandler < MyRequest > { public Task<Unit> Handle ( MyRequest request, CancellationToken cancellationToken ) { // do stuff return Task.FromResult(Unit.Value); } }
El envío de notificaciones es muy similar al envío de solicitudes, en el sentido de que se debe crear un objeto de notificación y un objeto de controlador de notificaciones. La diferencia aquí es que se pueden crear múltiples objetos del controlador de notificaciones, que se llamarán cuando se envíe una notificación a MediatR.
public class MyNotification : INotification { // some properties } public class MyNotificationHandler1 : INotificationHandler < MyNotification > { public Task Handle ( MyNotification notification, CancellationToken cancellationToken ) { // do stuff return Task.CompletedTask; } } public class MyNotificationHandler2 : INotificationHandler < MyNotification > { public Task Handle ( MyNotification notification, CancellationToken cancellationToken ) { // do stuff return Task.CompletedTask; } }
Luego, para enviar la notificación, llame al método Publish en la instancia de IMediator, pasando una instancia de su objeto de notificación. Cuando se llama a Publish, se ejecutarán tanto MyNotificationHandler1 como MyNotificationHandler2.
public class MyService { private readonly IMediator _mediator; public MyService ( IMediator mediator ) { _mediator = mediator; } public async Task Execute ( ) { var notification = new MyNotification { // initialise }; await _mediator.Publish(notification); } }
Los comportamientos de canalización son un tipo de middleware que se ejecuta antes y después de una solicitud (solo admite solicitudes, no notificaciones). Pueden ser útiles para una serie de tareas diferentes, como registro, manejo de errores, validación de solicitudes, etc.
Estos comportamientos funcionan de la misma manera que esperaría para el middleware: puede encadenar varios comportamientos juntos, cada comportamiento se ejecuta a su vez hasta que llega al final de la cadena, luego se ejecuta el controlador de solicitud real, luego el resultado de esto es pasado de vuelta a la cadena.
Por ejemplo, un LoggingBehaviour podría escribir en el registro de la aplicación antes y después de cada solicitud:
public class LoggingBehavior < TRequest , TResponse > : IPipelineBehavior < TRequest , TResponse > { private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger; public LoggingBehavior ( ILogger<LoggingBehavior<TRequest, TResponse>> logger ) { _logger = logger; } public async Task<TResponse> Handle ( TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next ) { _logger.LogInformation( $"Handling { typeof (TRequest).Name} " ); // go to the next behaviour in the chain/to the request handler var response = await next(); _logger.LogInformation( $"Handled { typeof (TResponse).Name} " ); return response; } }
En ASP NET Core, para registrar cada PipelineBehaviour con el contenedor IoC, agregue la siguiente línea al método ConfigureServices de la clase Startup:
services.AddTransient( typeof (IPipelineBehavior<,>), typeof (LoggingBehaviour<,>));
Para otros contenedores, consulta la wiki .
En este artículo, presenté el patrón de mediador y el paquete NuGet MediatR, que en sí mismo es una implementación del patrón de mediador. Le mostré cómo enviar solicitudes (uno a uno) y notificaciones (uno a muchos), así como también cómo escribir middleware (comportamientos de canalización) que se ejecuta antes o después de cada solicitud.
Libro electrónico "Diez++ formas de ganar dinero como desarrollador"
Publico principalmente sobre el desarrollo web full stack .NET y Vue. Para asegurarse de no perderse ninguna publicación, siga este blog y suscríbase a mi boletín . Si te ha resultado útil esta publicación, dale me gusta y compártela. También puedes encontrarme en Twitter .