4

古い非 OWIN API では、MessageHanlder を使用してすべての HttpRequests と HttpResponses をログに記録します。MessageHandler は次のとおりです。

public class MessageHandler : DelegatingHandler
{
    private static readonly ILog RequestApiLogger = LogManager.GetLogger("RequestApiPacketLogger");
    private static readonly ILog ResponseApiLogger = LogManager.GetLogger("ResponseApiPacketLogger");

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var correlationId = Guid.NewGuid();

        RequestApiLogger.LogHttpRequest(request, correlationId);

        return await base.SendAsync(request, cancellationToken).ContinueWith(
            task =>
            {
                var response = task.Result;
                response.Headers.Add("http-tracking-id", correlationId.ToString("D"));
                ResponseApiLogger.LogHttpResponse(response, correlationId);
                return response;

            }, cancellationToken);
    }
}

ただし、私の新しいプロジェクトでは、カスタム OWIN ミドルウェアを作成して、次のように OwinContext を使用して同様のことを行うことができます。

//use an alias for the OWIN AppFunc
using AppFunc = Func<IDictionary<string, object>, Task>;

public class LoggingMiddleware
{
    private readonly AppFunc _next;

    public LoggingMiddleware(AppFunc next)
    {
        _next = next;
    }

    public async Task Invoke(IDictionary<string, object> environment)
    {
        IOwinContext context = new OwinContext(environment);

        // Get the identity 
        var identity = (context.Request.User != null && context.Request.User.Identity.IsAuthenticated)
            ? context.Request.User.Identity.Name
            : "(anonymous)";

        // Buffer the request (body is a string, we can use this to log the request later
        var requestBody = new StreamReader(context.Request.Body).ReadToEnd();
        var requestData = Encoding.UTF8.GetBytes(requestBody);
        context.Request.Body = new MemoryStream(requestData);

        var apiPacket = new ApiPacket
        {
            CallerIdentity = identity,
            Request = requestBody,
            RequestLength = context.Request.Body.Length
        };

        // Buffer the response
        var responseBuffer = new MemoryStream();
        var responseStream = context.Response.Body;
        context.Response.Body = responseBuffer;

        // add the "http-tracking-id" response header so the user can correlate back to this entry
        var responseHeaders = (IDictionary<string, string[]>)environment["owin.ResponseHeaders"];
        responseHeaders["http-tracking-id"] = new[] { apiPacket.TrackingId.ToString("d") };

        await _next.Invoke(environment);

        responseBuffer.Seek(0, SeekOrigin.Begin);
        var reader = new StreamReader(responseBuffer);
        apiPacket.Response = await reader.ReadToEndAsync();
        apiPacket.ResponseLength = context.Response.ContentLength ?? 0;

        WriteRequestHeaders(context.Request, apiPacket);
        WriteResponseHeaders(context.Response, apiPacket);

        // You need to do this so that the response we buffered is flushed out to the client application.
        responseBuffer.Seek(0, SeekOrigin.Begin);
        await responseBuffer.CopyToAsync(responseStream);

        //TODO: persist the ApiPacket in the database
    }

    private static void WriteRequestHeaders(IOwinRequest request, ApiPacket packet)
    {
        packet.Verb = request.Method;
        packet.RequestUri = request.Uri;
        packet.RequestHeaders = "{\r\n" + string.Join(Environment.NewLine, request.Headers.Select(kv => "\t" + kv.Key + "=" + string.Join(",", kv.Value))) + "\r\n}";
    }

    private static void WriteResponseHeaders(IOwinResponse response, ApiPacket packet)
    {
        packet.StatusCode = response.StatusCode;
        packet.ReasonPhrase = response.ReasonPhrase;
        packet.ResponseHeaders = "{\r\n" + string.Join(Environment.NewLine, response.Headers.Select(kv => "\t" + kv.Key + "=" + string.Join(",", kv.Value))) + "\r\n}";
    }
}

log4net を使用して情報を SQL2012 データベースに書き込みます。どちらの方法でも私の目標を達成できます。ただし、ある方法を他の方法よりも使用する理由を探しています。カスタム OWIN ミドルウェアまたは MessageHandler を使用する必要がありますか? その理由は? 前もって感謝します。

4

2 に答える 2

0

すでにMessageHandler実装があるので、別の理由があるまでそれを使用することをお勧めします。

ただし、ロギングを に移動する正当な理由の 1 つは、そのロギング機能を必要とする (または恩恵を受ける)OwinMiddleware他のコンポーネントがある場合です (使用していると仮定すると、要求パイプライン)。OwinMiddlewareWebApiMessageHandlersOwinMiddleware

于 2016-02-16T21:51:51.913 に答える
0

OWINミドルウェアを使用するようです。MessageHandler 内で Principal.IIdentity がまだ解決されていないことがわかりました。たとえば、メッセージ ハンドラー、API コントローラーのコンストラクター、および API メソッドにブレークポイントを配置すると、次のように表示されます (順番に)。

メッセージ ハンドラーの使用

  1. MessageHandler > Principal.IIdentity では、まだ解決されていません。
  2. API コントローラーのコンストラクターで > Principal.IIDentity がまだ解決されていません。
  3. API コントローラーの GET メソッドでは、最後に Principal.IIdentity が解決されます。

したがって、許可されたユーザーの ID を引き出して MessageHandler に記録することはできません。

ただし、OWIN ミドルウェアを使用する場合、Principal.IIdentity はそこで解決されるため、その時点で userId をログ テーブルに書き込むことができます。これが、ミドルウェアを使用することにした理由です。

ただし、API プロジェクトで IIDentity がいつ設定されるかについて、誰かが明確に説明できるかもしれません。

于 2016-02-18T14:27:40.027 に答える