【问题标题】:Web API audit loggingWeb API 审计日志
【发布时间】:2012-08-31 07:05:44
【问题描述】:

我需要审核对我的 Web API 的日志调用,理想情况下我想使用一个属性,例如:

    [HttpPost, Auditing]
    public dynamic MyAPICall()

属性应该能够在执行之前和之后拦截 API 调用,以便记录参数以及 API 调用运行的时间。

使用 MVC,我可以创建一个 ActionFilterAttribute 派生并覆盖 OnActionExecuted 和 OnActionExecuting。

在 Web API 世界中是否有可能?

【问题讨论】:

标签: c# asp.net asp.net-web-api


【解决方案1】:

我开发了一个库,该库允许您使用操作过滤器记录与 ASP.NET Web API 控制器的交互。

它可以记录带有调用者信息、参数、输出、持续时间、异常等的操作方法调用。

看看Audit.WebApi

您可以使用以下命令快速创建使用此库的示例项目:

> dotnet new -i Audit.WebApi.Template
> dotnet new webapiaudit

【讨论】:

    【解决方案2】:

    Http 消息处理程序应该是一个很好的可扩展点。但要小心,并发请求内容读取可能存在一些问题。例如,Model Binder 可能会在 LoggingHandler 正在读取请求内容时尝试读取请求内容,但无法反序列化模型。要防止此类问题,只需将等待调用添加到 LogRequestLoggingInfo 方法。

    public class LoggingHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // Log the request information
            LogRequestLoggingInfo(request);
    
            // Execute the request
            return base.SendAsync(request, cancellationToken).ContinueWith(task =>
            {
                var response = task.Result;
                // Extract the response logging info then persist the information
                LogResponseLoggingInfo(response);
                return response;
            });
        }
    
        private void LogRequestLoggingInfo(HttpRequestMessage request)
        {
            if (request.Content != null)
            {
                request.Content.ReadAsByteArrayAsync()
                    .ContinueWith(task =>
                        {
                            var result = Encoding.UTF8.GetString(task.Result);
                            // Log it somewhere
                        }).Wait(); // !!! Here is the fix !!!
            }
        }
    
        private void LogResponseLoggingInfo(HttpResponseMessage response)
        {
            if (response.Content != null)
            {
                response.Content.ReadAsByteArrayAsync()
                    .ContinueWith(task =>
                    {
                        var responseMsg = Encoding.UTF8.GetString(task.Result);
                        // Log it somewhere
                    });
            }
        }
    }
    

    您可以阅读更多关于它的信息here

    【讨论】:

    【解决方案3】:

    我想你会感兴趣看看 Web API tracking http://www.asp.net/web-api/overview/testing-and-debugging/tracing-in-aspnet-web-api。它允许您查看 Web API 的内部机制。

    在您的情况下,我假设您对操作的输入和输出特别感兴趣。因此,您可以像以下示例一样对 TraceWriter 进行过滤以过滤掉冗余信息:

    public class ActionAuditor : ITraceWriter
    {
        private const string TargetOperation = "ExecuteAsync";
        private const string TargetOpeartor = "ReflectedHttpActionDescriptor";
    
        public void Trace(HttpRequestMessage request, string category, TraceLevel level, Action<TraceRecord> traceAction)
        {
            var rec = new TraceRecord(request, category, level);
            traceAction(rec);
    
            if (rec.Operation == TargetOperation && rec.Operator == TargetOpeartor)
            {
                if (rec.Kind == TraceKind.Begin)
                {
                    // log the input of the action
                }
                else
                {
                    // log the output of the action
                }
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      我会使用消息处理程序而不是属性。

      public class LoggingHandler : DelegatingHandler
      {
          protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
          {
              LogRequest(request);
      
              return base.SendAsync(request, cancellationToken).ContinueWith(task =>
              {
                  var response = task.Result;
      
                  LogResponse(response);
      
                  return response;
              });
          }
      
          private void LogRequest(HttpRequestMessage request)
          {
              (request.Content ?? new StringContent("")).ReadAsStringAsync().ContinueWith(x =>
              {
                  Logger.Info("{4:yyyy-MM-dd HH:mm:ss} {5} {0} request [{1}]{2} - {3}", request.GetCorrelationId(), request.Method, request.RequestUri, x.Result, DateTime.Now, Username(request));
              });
          }
      
          private void LogResponse(HttpResponseMessage response)
          {
              var request = response.RequestMessage;
              (response.Content ?? new StringContent("")).ReadAsStringAsync().ContinueWith(x =>
              {
                  Logger.Info("{3:yyyy-MM-dd HH:mm:ss} {4} {0} response [{1}] - {2}", request.GetCorrelationId(), response.StatusCode, x.Result, DateTime.Now, Username(request));
              });
          }
      
          private string Username(HttpRequestMessage request)
          {
              var values = new List<string>().AsEnumerable();
              if (request.Headers.TryGetValues("my-custom-header-for-current-user", out values) == false) return "<anonymous>";
      
              return values.First(); 
          }
      }
      

      【讨论】:

      • 如何分析该日志?在 sharepoint 中创建仪表板并定义 kpi 列表?
      • 这只是捕获用于记录的信息。记录方式/内容甚至如何查看日志的详细信息是另一回事。一个独立于这个问题的。
      • @JasonMeckley 你如何在api controller 中使用LoggingHandler
      • 此实现旨在记录请求/响应。如果您需要控制器中的记录器,请将另一个记录器传递给控制器​​,有多种选择来完成此操作。
      猜你喜欢
      • 2018-04-26
      • 2018-01-25
      • 2019-10-12
      • 2011-10-24
      • 2020-05-04
      • 2020-04-13
      • 2011-08-05
      • 2010-10-11
      • 2012-10-01
      相关资源
      最近更新 更多