0

このブログ投稿DelegatingHandlerの詳細を使用して、リクエスト ログを作成しました。

リクエストまたはレスポンスの本文を読みたくない (この作業を 2 倍にするのは、潜在的に大量の Web サービスではばかげているように思われる)。やりたいことは、各リクエストに一意の ID を割り当て、URI とヘッダーをログに記録することだけです。別のヘッダーの応答に要求 ID を書き込み、応答 (成功/失敗) と発生した例外をログに記録します。

protected override System.Threading.Tasks.Task<HttpResponseMessage> 
  SendAsync(HttpRequestMessage request, 
  System.Threading.CancellationToken cancellationToken)
{
  DateTime receivedUTC = DateTime.UtcNow;

  //I use the Request properties to persist a Request's ID
  var requestID = request.GetRequestUID();
  if (requestID == null)
    requestID = request.SetRequestUID();

  //grab the base response task
  var baseResult = base.SendAsync(request, cancellationToken);

  return baseResult.ContinueWith(innerTask =>
  {
    var tcs = new TaskCompletionSource<HttpResponseMessage>();

    //note I've got rid of SynchronizationContext code out of this
    //to keep it shorter

    //construct the log packet
    LogData toLog = new LogData()
        {
          ReceivedUTC = receivedUTC,
          Request = request,
          RequestID = requestID,
        };

    //get the response
    try
    {
      tcs.SetResult(innerTask.Result);
      //NOTE - If this request actually fails response serialization,
      //       Then the above result will actually look fine, because
      //       The error hasn't occurred yet!
      toLog.Response = innerTask.Result;
      //this adds a header
      AddRequestIDToResponse(toLog.Response, requestID);
    }
    catch (Exception ex)
    {
      tcs.TrySetException(ex);
      toLog.Ex = ex;
    }

    //fire the logging call asynchronously (code elided, just some DB work)
    Task.Factory.StartNew(() => Log(toLog));
    return tcs.Task;
  }).Unwrap();
}

ObjectContentこれは、アクションメソッドから返されたものが応答にシリアル化される 間に例外が発生した場合を除いて、ほぼすべての要求に対して完全に正常に機能します。

これが発生した場合、上記のコードは既に実行されており、上記の try/catch ブロックに表示される応答メッセージは、最終的にシリアル化に失敗するオブジェクトを含む200通常のメッセージとして表示されます。ObjectContent応答本文へのシリアル化がまだ行われていないため、これは理にかなっています。

コンテンツのフォーマットが行われた後に表示される応答メッセージが、クライアントが受け取る実際のObjectContentメッセージであることを確認するには、このコードをどのように変更すればよいでしょうか? 別の拡張ポイントを見る必要がありますか?

4

1 に答える 1

3

誰かが(うまくいけば)やって来て、私が間違っていることを証明するまでの暫定的な答えとして。膨大な量のコードをコピーして貼り付けなければ、Web API パイプライン自体の中でこれを行うことはほとんど不可能に近いと思われます。

コンテンツのシリアライゼーションは、Web API パイプラインの最上部でトリガーされますHttpControllerHandler。ここで、はと呼ばれる内部静的メソッドでHttpContent、基になる にコピーされます。Web API パイプライン内で実際の応答をログに記録できるように、適切な場所にタスクを挿入できるようにするための十分な拡張ポイントがクラス自体にありません。HttpResponseOutputStreamHttpControllerHandler.ConvertResponse

だから私は直面しています:

  • ソースコードから全体を持ち上げHttpControllerHandlerて、それを私のプロジェクトにインポートし(そしてそれが使用するすべての内部構造、これは良い考えではありません)、それに応じてカスタマイズします。

  • シリアライゼーションを早期に強制して例外をキャッチするだけです。例外はログに記録できますが、応答はログに記録できません。ただし、これには 1 つの小さな問題があります
    。リクエスト ID をレスポンスに書き込むことは非常に重要です。これらのフォーマット例外が発生すると、レスポンス全体が エラー レスポンスに置き換え
    られるため、ID は書き込まれません。HttpControllerHandler

  • Web API の次のレベルでリクエストをログに記録します。Web API要求のみをログに記録する必要があるため、これ
    は理想的ではありません。また、ロギング コードは、 データベース接続 (マルチテナント Web サービス) を解決するため の要求固有の DI コンテナーを取得するために、現在の要求の HttpConfiguration オブジェクトに 依存しています。


最終的に唯一の現実的なオプションは、IIS または Asp.Net レベルで作業を行う最後のオプションです。したがって、Web API にはこれらすべての拡張ポイントがあるにもかかわらず、実際にはその中に「完全な」ログ ソリューションを実装することはできません。これは本当に残念なことです。

于 2012-08-31T11:22:16.420 に答える