diff --git a/Directory.Packages.props b/Directory.Packages.props index 4897852..f52b3e1 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,9 +1,11 @@ + + diff --git a/src/Ardalis.SharedKernel/Ardalis.SharedKernel.csproj b/src/Ardalis.SharedKernel/Ardalis.SharedKernel.csproj index 4b0ceb3..c8e6bc6 100644 --- a/src/Ardalis.SharedKernel/Ardalis.SharedKernel.csproj +++ b/src/Ardalis.SharedKernel/Ardalis.SharedKernel.csproj @@ -13,9 +13,9 @@ https://github.com/ardalis/Ardalis.SharedKernel DDD;Shared Kernel;SharedKernel;Domain-Driven Design;Repository;Specification;ValueObject;Value Object;Ardalis;Clean;Clean Architecture;Clean Architecture Template icon.png - 1.2.0 + 1.3.0 - * Add Commands, Queries, and Handler interfaces + * Adding LoggingBehavior true true @@ -24,8 +24,10 @@ + + diff --git a/src/Ardalis.SharedKernel/LoggingBehavior.cs b/src/Ardalis.SharedKernel/LoggingBehavior.cs new file mode 100644 index 0000000..27e8067 --- /dev/null +++ b/src/Ardalis.SharedKernel/LoggingBehavior.cs @@ -0,0 +1,63 @@ +using System.Diagnostics; +using System.Reflection; +using Ardalis.GuardClauses; +using MediatR; +using Microsoft.Extensions.Logging; + +namespace Ardalis.SharedKernel; + +/// +/// Adds logging for all requests in MediatR pipeline. +/// Configure by adding the service with a scoped lifetime +/// +/// Example for Autofac: +/// builder +/// .RegisterType<Mediator>() +/// .As<IMediator>() +/// .InstancePerLifetimeScope(); +/// +/// builder +/// .RegisterGeneric(typeof(LoggingBehavior<,>)) +/// .As(typeof(IPipelineBehavior<,>)) +/// .InstancePerLifetimeScope(); +/// +/// +/// +/// +public class LoggingBehavior : IPipelineBehavior + where TRequest : IRequest +{ + private readonly ILogger _logger; + + public LoggingBehavior(ILogger logger) + { + _logger = logger; + } + + public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken) + { + Guard.Against.Null(request); + if (_logger.IsEnabled(LogLevel.Information)) + { + _logger.LogInformation("Handling {RequestName}", typeof(TRequest).Name); + + // Reflection! Could be a performance concern + Type myType = request.GetType(); + IList props = new List(myType.GetProperties()); + foreach (PropertyInfo prop in props) + { + object? propValue = prop?.GetValue(request, null); + _logger.LogInformation("Property {Property} : {@Value}", prop?.Name, propValue); + } + } + + var sw = Stopwatch.StartNew(); + + var response = await next(); + + _logger.LogInformation("Handled {RequestName} with {Response} in {ms} ms", typeof(TRequest).Name, response, sw.ElapsedMilliseconds); + sw.Stop(); + return response; + } +} + diff --git a/src/Ardalis.SharedKernel/MediatRDomainEventDispatcher.cs b/src/Ardalis.SharedKernel/MediatRDomainEventDispatcher.cs index 7bd84a0..210d9ce 100644 --- a/src/Ardalis.SharedKernel/MediatRDomainEventDispatcher.cs +++ b/src/Ardalis.SharedKernel/MediatRDomainEventDispatcher.cs @@ -1,4 +1,5 @@ -using MediatR; +using System; +using MediatR; namespace Ardalis.SharedKernel; @@ -24,3 +25,4 @@ public async Task DispatchAndClearEvents(IEnumerable entitiesWithEve } } } +