Click here for step by step implementation of the CQRS MediatR design pattern.
In this article, we are going to do request logging into an Asp.Net application Core application build on the CQRS MediatR design pattern. The application request logging helps to track the time taken per request. The MediatR provides a pipeline interface that is 'IPipelineBehavior' that helps to implement our logging logic.
IPipelineBehavior:
The 'IPipelineBehavior' exactly works like Asp.Net Core middleware, but its starting execution and ending execution happens within the 'IMediator'. So the 'IMediator.send()' is usually used to invoke the 'Query' or 'Command' handlers. So if we implement 'IPipelineBehavior' then begin logic inside of its start executes then invokes 'Query' or 'Command' handlers, later again go through 'IPipelineBehavior' and executes the end logic.Create A .Net5 Web API Sample Application:
In this demo our main focus on MediatR IPipelineBehavior implementation. Let's create a sample .Net5 Web API application to accomplish our demo.
Install MediatR Package:
Package Manager Command:
Install-Package MediatR -Version 9.0.0
.Net CLI
dotnet add package MediatR --version 9.0.0
Install-Package MediatR -Version 9.0.0
.Net CLI
dotnet add package MediatR --version 9.0.0
Package Manager Command:
Install-Package MediatR.Extensions.Microsoft.DependencyInjection -Version 9.0.0
.Net CLI
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection --version 9.0.0
Install-Package MediatR.Extensions.Microsoft.DependencyInjection -Version 9.0.0
.Net CLI
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection --version 9.0.0
Register MediatR Service:
In 'Startup.cs' register the MediatR service, which helps to inject the 'IMediator' interface into the API controller.
Startup.cs:
services.AddMediatR(Assembly.GetExecutingAssembly());
Implement IPipelineBehavior For Request Logging:
Now let's implement our request logging by implementing the 'IPipelineBehavior'. So lets create a folder like 'Pipelines' and a file like 'AppLoggingBehavior.cs'.
Pipelines/AppLoggingBehavior.cs:
using MediatR; using Microsoft.Extensions.Logging; using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace CQRSSimpleRequestLog.Learn.Pipelines { public class AppLoggingBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> { private readonly ILogger<AppLoggingBehaviour<TRequest, TResponse>> _logger; public AppLoggingBehaviour(ILogger<AppLoggingBehaviour<TRequest, TResponse>> logger) { _logger = logger; } public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next) { string requestName = typeof(TRequest).Name; string unqiueId = Guid.NewGuid().ToString(); _logger.LogInformation($"Begin Request Id:{unqiueId}, request name:{requestName}"); var timer = new Stopwatch(); timer.Start(); var response = await next(); timer.Stop(); _logger.LogInformation($"Begin Request Id:{unqiueId}, request name:{requestName}, total request time:{timer.ElapsedMilliseconds}"); return response; } } }
- (Line: 10) Implementing the 'IPipelineBehavior<TRequest, TResponse>'.
- (Line: 12-16) Injecting the 'ILogger' interface, using this we can either log to 'console', 'file', and 'database'. For this demo, we will target the 'console' log.
- (Line: 17) The 'Handle' method of 'IPipelineBehvior' will executes automatically.
- (Line: 19) Name of the request model.
- (Line: 20) Creating a unique id to determine the starting log and ending log.
- (Line: 21) Initial log information for our request.
- (Line: 22-23) Initialized 'StopWatch' instance.
- (Line: 24) Here awaiting 'RequestHandlerDelegate<TResponse>', so from here code execution either shift to 'IPipelineBehavior' if other exist or shift to the 'Handler'(like Query or Command).
- (Line: 25) This line of code executes after completion of the 'Handler' execution which means now code executes in the backward direction.
- (LIne: 26) Finally logging the end request and its time taken into the console.
Startup.cs:
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(AppLoggingBehaviour<,>))
Create A Test Endpoint:
Now let's implement an endpoint using the CQRS MediatR pattern to determine how our IPipelineBehavior works. In this demo I briefly show the CQRS MediatR pattern, please click here for step by step implementation of CQRS MediatR
Let's create a response model like 'ProductResponseModel.cs' in the 'ResponseModels' folder.
ResponseModels/ProductResponseModel.cs:
namespace CQRSSimpleRequestLog.Learn.ResponseModels { public class ProductResponseModel { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } } }Let's create a request model like 'GetProductRequestModel' in the 'RequestModels' folder.
RequestModels/GetProductRequestModel.cs:
using CQRSSimpleRequestLog.Learn.ResponseModels; using MediatR; namespace CQRSSimpleRequestLog.Learn.RequestModels { public class GetProductRequestModel : IRequest<ProductResponseModel> { } }Now add our query handler file like 'GetProductQueryHandler.cs' in the 'Handlers/Query' folder
Handlers/Query/GetProductQueryHandler.cs:
using CQRSSimpleRequestLog.Learn.RequestModels; using CQRSSimpleRequestLog.Learn.ResponseModels; using MediatR; using System.Threading; using System.Threading.Tasks; namespace CQRSSimpleRequestLog.Learn.Handlers { public class GetProductQueryHandler : IRequestHandler<GetProductRequestModel, ProductResponseModel> { public async Task<ProductResponseModel> Handle(GetProductRequestModel request, CancellationToken cancellationToken) { await Task.FromResult(0); return new ProductResponseModel { Id = 1, Name = "Remote Car", Price = 200 }; } } }Let's add an action method to invoke our query handler as below.
Controllers/ProductController.cs:
using CQRSSimpleRequestLog.Learn.RequestModels; using MediatR; using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; namespace CQRSSimpleRequestLog.Learn.Controllers { [Route("api/[controller]")] [ApiController] public class ProductController : ControllerBase { private readonly IMediator _mediator; public ProductController(IMediator mediator) { _mediator = mediator; } [HttpGet] [Route("get")] public async Task<IActionResult> GetProducts() { var result = await _mediator.Send(new GetProductRequestModel()); return Ok(result); } } }
- (Line: 22) The '_mediator.Send()' method entry point of the mediator. Here it first executes all the 'IPipelineBehavior' implementations request logic and then executes the 'Handlers' and then again executes all the 'IPipelineBehvior' implementation response logic.
Video Session:
Support Me!
Buy Me A Coffee
PayPal Me
Wrapping Up:
Hopefully, I think this article delivered some useful information on the MediatR IPipelineBehavior implementation in Asp.Net Core. I love to have your feedback, suggestions, and better techniques in the comment section below.
Comments
Post a Comment