使用 OWIN 中间件或委派的消息处理程序来记录 api 请求/响应



在我的旧非OWIN API中,我使用MessageHanlder来记录所有HttpRequests和HttpResponses。下面是消息处理程序:

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 = "{rn" + string.Join(Environment.NewLine, request.Headers.Select(kv => "t" + kv.Key + "=" + string.Join(",", kv.Value))) + "rn}";
    }
    private static void WriteResponseHeaders(IOwinResponse response, ApiPacket packet)
    {
        packet.StatusCode = response.StatusCode;
        packet.ReasonPhrase = response.ReasonPhrase;
        packet.ResponseHeaders = "{rn" + string.Join(Environment.NewLine, response.Headers.Select(kv => "t" + kv.Key + "=" + string.Join(",", kv.Value))) + "rn}";
    }
}

我正在使用log4net将信息写入SQL2012数据库。这两种方式都实现了我的目标。但是,我正在寻找使用一种方法而不是另一种方法的理由。我应该使用自定义 OWIN 中间件还是消息处理程序,为什么?提前谢谢。

由于您已经拥有MessageHandler实现,因此我建议您使用它,直到您有其他原因为止。

但是,在我的头顶上,将日志记录移动到OwinMiddleware的一个有效原因是,如果您有其他需要(或将从中受益(该日志记录功能的OwinMiddleware组件(假设您正在使用WebApi,因此MessageHandlers将在请求管道中的所有OwinMiddleware之后运行(。

看起来我将使用 OWIN 中间件。我发现在消息处理程序中,Principal.IIdentity尚未解决。例如,如果我将断点放在消息处理程序、API 控制器的构造函数和 API 方法中,这就是我看到的(按顺序(。

使用消息处理程序

  1. 在 MessageHandler> Principal.IIdentity 尚未解析。
  2. 在 API 控制器的构造函数中> Principal.IIDentity 尚未解析。
  3. 在 API 控制器的 GET 方法中,最终解析了 Principal.IIdentity。

因此,我无法在消息处理程序中提取并记录授权用户的 ID。

但是,当使用 OWIN 中间件时,Principal.IIdentity 在那里解析,因此我可以在此时将 userId 写入我的日志表。这就是我决定使用中间件的原因。

也许有人可以澄清何时在 API 项目中设置 IIDentity。

相关内容

  • 没有找到相关文章

最新更新