我需要审核对我的 Web API 的日志调用,理想情况下我想使用一个属性,例如:
[HttpPost, Auditing]
public dynamic MyAPICall()
属性应该能够在执行之前和之后拦截 API 调用,以便记录参数以及 API 调用运行的时间。
使用 MVC,我可以创建一个 ActionFilterAttribute 派生并覆盖 OnActionExecuted 和 OnActionExecuting。
Web API 世界中的等价物是否可行?
我需要审核对我的 Web API 的日志调用,理想情况下我想使用一个属性,例如:
[HttpPost, Auditing]
public dynamic MyAPICall()
属性应该能够在执行之前和之后拦截 API 调用,以便记录参数以及 API 调用运行的时间。
使用 MVC,我可以创建一个 ActionFilterAttribute 派生并覆盖 OnActionExecuted 和 OnActionExecuting。
Web API 世界中的等价物是否可行?
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
});
}
}
}
你可以在这里阅读更多关于它的信息。
我会使用消息处理程序而不是属性。
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();
}
}
我想你会有兴趣看看 Web API 跟踪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
}
}
}
}
我研究了一个库,它允许您使用操作过滤器记录与 ASP.NET Web API 控制器的交互。
它可以记录带有调用者信息、参数、输出、持续时间、异常等的操作方法调用。
看看Audit.WebApi。
您可以使用以下命令快速创建使用此库的示例项目:
> dotnet new -i Audit.WebApi.Template
> dotnet new webapiaudit