ASP.NET Core MediatRのパイプラインでログを出力する
ASP.NET Coreのプロジェクトで、MediatRのパイプライン機能を利用してログを出力を行います。
ASP.NET Coreに導入したMediatRのラッパークラスを作成するで紹介した構成に、ログ出力のパイプラインを追加します。
パッケージのインストール
アプリケーション層でログ出力できるようにMicrosoft.Extensions.Loggingのパッケージをインストールします。
$ cd App.Application # アプリケーション層に移動
$ dotnet add package Microsoft.Extensions.LoggingIPipelineBehaviorの作成
MediatRにはハンドラ処理の前後に処理を組み込む仕組みがあります。
IPipelineBehaviorを継承したクラスを作成することにより、この仕組みを実現します。
以下のように、実装します。
LoggingBehavior.csusing MediatR;
using Microsoft.Extensions.Logging;
namespace App.Application.Core;
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
    where TResponse : IResult
{
    private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;
    public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger)
    {
        _logger = logger;
    }
    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        _logger.LogInformation("処理開始: " + typeof(TRequest).Name);
        var response = await next();
        _logger.LogInformation("処理終了: " + typeof(TRequest).Name);
        return response;
    }
}ジェネリックのTRequestには入力クラス、TResponseには出力クラスが対応しています。
whereで入力クラスと出力クラスを指定することにより、特定のハンドラのみパイプライン処理を行うような動作が可能です。
今回はすべてのハンドラでバリデーションチェックを行いたいので、以下のように指定しています。
入力クラスはIRequest<TResponse>としているため、実質すべての入力クラスが対象となります。(MediatRを使用する場合は全ての入力クラスはIRequestを継承しているため)
IResultはASP.NET Coreに導入したMediatRのラッパークラスを作成するで定義したインターフェースです。全ての出力クラスはIResultを継承するように作成していますので、こちらも実質全ての出力クラスが対象となります。
nextの処理で、実際のハンドラが実行されますので、その前後でログ出力を行っています。
DIコンテナに登録
アプリケーション層でDIコンテナに登録する処理で、上記で作成したLoggingBehaviorをDIに登録します。
public static IServiceCollection AddApplication(this IServiceCollection services)
{
    services.AddMediatR(Assembly.GetExecutingAssembly());
    services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
    return services;
}以上で設定は完了です。
動作確認
以下のようにWeb層(プレゼン層)からMediatRを使用してアプリケーション層の処理をコールします。
var result = await mediator.Send(new SampleUpdateCommand(data));コンソールに以下のログが出力されることが確認できます。
info: App.Application.Core.LoggingBehavior[0]
      Handling Action: SampleUpdateCommand
info: App.Application.Core.LoggingBehavior[0]
      Handled Action: SampleUpdateCommand