ASP.NET WebAPIで要求と応答のメタデータをログに記録する方法

認証、キャッシング、例外管理と同様に、ロギングは横断的関心事(アプリケーション全体に影響を与える機能)であり、一元化する必要があります。多くの場合、メソッド呼び出しやイベントのシーケンス、ユーザーアクション、またはアプリケーションの実行時に発生する可能性のあるエラーを含む可能性のあるアプリケーションデータをログに記録します。利用できるログフレームワークはたくさんありますが、この記事では、ASP.NET WebAPIで要求と応答をログに記録する方法に焦点を当てます。

Web APIでの要求と応答のログ記録は、着信および発信サービス呼び出しのデバッグ、トレース、および検査に役立ちます。すべてのリクエストとレスポンスを1か所に記録することで、リクエストとレスポンスの問題を簡単に検出できます。この投稿では、WebAPIでリクエストとレスポンスを監視およびログに記録するカスタムメッセージハンドラーを作成します。メッセージハンドラは、通話を傍受し、すべての要求と応答を1か所に一元的に記録するために使用されます。

WebAPIに横断的関心事を注入するための戦略

WebAPIにロギングやその他の横断的関心事を注入する方法は複数あります。 1つの方法は、カスタムApiControllerクラス、またはすべてのコントローラーの基本クラスを作成してから、ExecuteAsyncメソッドをオーバーライドすることです。別の方法は、カスタムアクションフィルターを使用することです。ただし、これらの戦略には両方とも制限があります。前者の場合、すべてのコントローラーがカスタム基本コントローラークラスを拡張することを確認する必要があります。後者の場合、使用するすべてのコントローラーにフィルターが適用されていることを確認する必要があります。

私の意見では、メッセージハンドラーを使用するのが最善の戦略です。これは、メッセージハンドラーを一度だけ記述してから、1か所に登録するためです。また、カスタムメッセージハンドラーはパイプラインのかなり早い段階、つまりHttpControllerDispatcherの前でも呼び出されるため、横断的関心事を注入するのに適しています。ちなみに、メッセージハンドラは、抽象HttpMessageHandlerクラスを継承するクラスです。したがって、この投稿では、メッセージハンドラーを利用してカスタムロガーを挿入します。

この投稿に示されているソースコードをビルドして実行する場合は、システムでVisualStudioを起動して実行する必要があります。また、NLogがインストールされている必要があります。NLogをインストール、構成、および使用する方法を知りたい場合は、こちらのNLogに関する私の記事をご覧ください。  

WebAPI用のカスタマーロガーの構築

VisualStudioで新しいWebAPIプロジェクトを作成し、目的の名前で保存します。ここでは、カスタム委任ハンドラーを利用して、WebAPIへの呼び出しをインターセプトします。まず、リクエストとレスポンスからのすべての情報を格納するカスタムPOCOクラスを作成しましょう。

パブリッククラスLogMetadata

    {{

        public string RequestContentType {get; セットする; }

        パブリック文字列RequestUri {get; セットする; }

        public string RequestMethod {get; セットする; }

        public DateTime?RequestTimestamp {get; セットする; }

        public string ResponseContentType {get; セットする; }

        public HttpStatusCode ResponseStatusCode {get; セットする; }

        public DateTime?ResponseTimestamp {get; セットする; }

    }

次に、LogHandlerというカスタムクラスを実装します。これは基本的に、DelegatingHandlerクラスを拡張するメッセージハンドラーです。

パブリッククラスCustomLogHandler:DelegatingHandler

    {{

        保護されたオーバーライド非同期タスクSendAsync(HttpRequestMessage request、CancellationToken cancelToken)

        {{

           base.SendAsync(request、cancelToken);を返します。

        }

    }

次のコードスニペットは、リクエストメタデータを作成する方法を示しています。このメソッドは、カスタムメッセージハンドラーのSendAsyncメソッドから呼び出され、LogMetadataクラスのインスタンスを返します。

プライベートLogMetadataBuildRequestMetadata(HttpRequestMessageリクエスト)

    {{

        LogMetadataログ=新しいLogMetadata

        {{

            RequestMethod = request.Method.Method、

            RequestTimestamp = DateTime.Now、

            RequestUri = request.RequestUri.ToString()

        };

        ログを返す;

    }

次に行う必要があるのは、応答オブジェクトからの情報でログメタデータインスタンスを更新することです。これを実現する方法は次のとおりです。

プライベートLogMetadataBuildResponseMetadata(LogMetadata logMetadata、HttpResponseMessage応答)

    {{

        logMetadata.ResponseStatusCode = response.StatusCode;

        logMetadata.ResponseTimestamp = DateTime.Now;

        logMetadata.ResponseContentType = response.Content.Headers.ContentType.MediaType;

        logMetadataを返します。

    }

参考までに、カスタムメッセージハンドラーの完全なソースコードを次に示します。

パブリッククラスCustomLogHandler:DelegatingHandler

    {{

        保護されたオーバーライド非同期タスクSendAsync(HttpRequestMessage request、CancellationToken cancelToken)

        {{

            var logMetadata = BuildRequestMetadata(request);

            var response = await base.SendAsync(request、cancelToken);

            logMetadata = BuildResponseMetadata(logMetadata、response);

            SendToLog(logMetadata);を待ちます。

            応答を返します。

        }

        プライベートLogMetadataBuildRequestMetadata(HttpRequestMessageリクエスト)

        {{

            LogMetadataログ=新しいLogMetadata

            {{

                RequestMethod = request.Method.Method、

                RequestTimestamp = DateTime.Now、

                RequestUri = request.RequestUri.ToString()

            };

            ログを返す;

        }

        プライベートLogMetadataBuildResponseMetadata(LogMetadata logMetadata、HttpResponseMessage応答)

        {{

            logMetadata.ResponseStatusCode = response.StatusCode;

            logMetadata.ResponseTimestamp = DateTime.Now;

            logMetadata.ResponseContentType = response.Content.Headers.ContentType.MediaType;

            logMetadataを返します。

        }

        プライベート非同期タスクSendToLog(LogMetadata logMetadata)

        {{

            // TODO:logMetadataインスタンスを事前設定されたログストアに保存するコードをここに記述します...

            trueを返します。

        }

    }

SendToLogメソッドに表示されるlogMetadataインスタンスを事前設定されたログターゲット(ファイルまたはデータベース)に保存するために必要なコードを記述する必要があることに注意してください。私はこのメタデータをログに記録するためにNLogを使用することを好みます。繰り返しになりますが、NLogに関する私の記事を参照して、これを行う方法を確認できます。

メッセージハンドラーの登録

カスタムメッセージハンドラーを登録するには、Global.asax.csファイルのApplication_StartイベントまたはWebApiConfigクラスのRegisterメソッドを利用できます。次のコードスニペットは、WebApiConfigクラスのRegisterメソッドを使用してハンドラーを登録する方法を示しています。

public static void Register(HttpConfiguration config)

    {{

      //ここにいつものコードを書いてください...

      config.MessageHandlers.Add(new CustomLogHandler());

    }

この記事では、カスタムメッセージハンドラーを使用してWebAPIでリクエストとレスポンスをログに記録する方法を検討しました。メッセージハンドラーは、横断的関心事をWebAPIパイプラインに注入するための優れた方法です。カスタムApiControllerクラスやカスタムアクションフィルターなど、Web APIにログインを挿入する方法は他にもありますが、カスタムメッセージハンドラーを使用する方が簡単です。要件に基づいてこの実装を自由に調整できます。たとえば、カスタムメタデータを追加できます。

ASP.NETおよびASP.NETCoreでさらに多くのことを行う方法:

  • ASP.NETCoreでメモリ内キャッシュを使用する方法
  • ASP.NET WebAPIでエラーを処理する方法
  • 複数のパラメーターをWebAPIコントローラーメソッドに渡す方法
  • ASP.NET WebAPIで要求と応答のメタデータをログに記録する方法
  • ASP.NETでHttpModuleを操作する方法
  • ASP.NET Core WebAPIの高度なバージョン管理
  • ASP.NETCoreで依存性注入を使用する方法
  • ASP.NETでセッションを操作する方法
  • ASP.NETでHTTPHandlerを操作する方法
  • ASP.NETCoreでIHostedServiceを使用する方法
  • ASP.NETCoreでWCFSOAPサービスを利用する方法
  • ASP.NETCoreアプリケーションのパフォーマンスを向上させる方法
  • RestSharpを使用してASP.NETCore WebAPIを使用する方法
  • ASP.NETCoreでのログインの操作方法
  • ASP.NETCoreでMediatRを使用する方法
  • ASP.NETCoreでセッション状態を操作する方法
  • ASP.NETCoreでナンシーを使用する方法
  • ASP.NET WebAPIのパラメーターバインディングを理解する
  • ASP.NET CoreMVCでファイルをアップロードする方法
  • ASP.NET Core WebAPIでグローバル例外処理を実装する方法
  • ASP.NETCoreでヘルスチェックを実装する方法
  • ASP.NETでのキャッシュのベストプラクティス
  • .NETでApacheKafkaメッセージングを使用する方法
  • WebAPIでCORSを有効にする方法
  • WebClientとHttpClientとHttpWebRequestをいつ使用するか
  • .NETでRedisキャッシュを操作する方法
  • .NETでTask.WaitAllとTask.WhenAllを使用する場合