C# Web API审核日志
我需要审核对Web API的日志调用,理想情况下,我希望使用一个属性,比如:C# Web API审核日志,c#,asp.net,asp.net-web-api,C#,Asp.net,Asp.net Web Api,我需要审核对Web API的日志调用,理想情况下,我希望使用一个属性,比如: [HttpPost, Auditing] public dynamic MyAPICall() 该属性应该能够在执行前后截获API调用,以便记录参数以及API调用运行的时间 有了MVC,我可以创建ActionFilterAttribute派生并覆盖OnActionExecuted和OnActionExecuting 在Web API世界中是否可能实现等效功能?我将使用消息处理程序而不是属性 publi
[HttpPost, Auditing]
public dynamic MyAPICall()
该属性应该能够在执行前后截获API调用,以便记录参数以及API调用运行的时间
有了MVC,我可以创建ActionFilterAttribute派生并覆盖OnActionExecuted和OnActionExecuting
在Web API世界中是否可能实现等效功能?我将使用消息处理程序而不是属性
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();
}
}
公共类日志处理程序:DelegatingHandler
{
受保护的覆盖任务SendAsync(HttpRequestMessage请求,CancellationToken CancellationToken)
{
日志请求(请求);
返回base.sendaync(请求,取消令牌).ContinueWith(任务=>
{
var response=task.Result;
对数响应(响应);
返回响应;
});
}
私有无效日志请求(HttpRequestMessage请求)
{
(request.Content??new StringContent(“”)。ReadAsStringAsync()。ContinueWith(x=>
{
Logger.Info(“{4:yyyy-MM-dd HH:MM:ss}{5}{0}请求[{1}]{2}-{3}”,request.GetCorrelationId(),request.Method,request.RequestUri,x.Result,DateTime.Now,用户名(请求));
});
}
专用无效日志响应(HttpResponseMessage响应)
{
var request=response.RequestMessage;
(response.Content??new StringContent(“”)。ReadAsStringAsync()。ContinueWith(x=>
{
Logger.Info(“{3:yyyy-MM-dd HH:MM:ss}{4}{0}响应[{1}]-{2}”,request.GetCorrelationId(),response.StatusCode,x.Result,DateTime.Now,用户名(请求));
});
}
私有字符串用户名(HttpRequestMessage请求)
{
var values=new List().AsEnumerable();
if(request.Headers.TryGetValues(“当前用户的自定义头”,out values)==false)返回“”;
返回值。First();
}
}
我想您会对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
}
}
}
}
公共类ActionAuditor:ITraceWriter
{
private const string TargetOperation=“ExecuteAsync”;
private const string targetoperator=“ReflectedHttpActionDescriptor”;
公共无效跟踪(HttpRequestMessage请求、字符串类别、TraceLevel、Action traceAction)
{
var rec=新跟踪记录(请求、类别、级别);
追踪反应(rec);
if(记录操作==TargetOperation&&rec.Operator==targetPeartor)
{
if(rec.Kind==TraceKind.Begin)
{
//记录操作的输入
}
其他的
{
//记录操作的输出
}
}
}
}
Http消息处理程序应该是一个很好的扩展点,用于此类目的。不过要小心,并发请求内容读取可能存在一些问题。例如,模型绑定器可能在LoggingHandler
读取请求内容时尝试读取请求内容,但未能对模型进行反序列化。要防止此类问题,只需向LogRequestLoggingInfo方法添加Wait调用
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
});
}
}
}
公共类日志处理程序:DelegatingHandler
{
受保护的覆盖任务SendAsync(HttpRequestMessage请求,CancellationToken CancellationToken)
{
//记录请求信息
LogRequestLoggingInfo(请求);
//执行请求
返回base.sendaync(请求,取消令牌).ContinueWith(任务=>
{
var response=task.Result;
//提取响应日志信息,然后保存该信息
LogResponseLogginInfo(响应);
返回响应;
});
}
私有void LogRequestLoggingInfo(HttpRequestMessage请求)
{
if(request.Content!=null)
{
request.Content.ReadAsByteArrayAsync()
.ContinueWith(任务=>
{
var result=Encoding.UTF8.GetString(task.result);
//把它记录在某个地方
}).Wait();/!!!这是修复方法!!!
}
}
专用无效日志响应LogginInfo(HttpResponseMessage响应)
{
if(response.Content!=null)
{
response.Content.ReadAsByteArrayAsync()
.ContinueWith(任务=>
{
var responseMsg=Encoding.UTF8.GetString(task.Result);
//把它记录在某个地方
});
}
}
}
您可以阅读更多信息。我开发了一个库,它允许您使用操作过滤器记录与ASP.NET Web API控制器的交互 它可以记录带有调用方信息、参数、输出、持续时间、异常等的操作方法调用 看一看 可以使用以下命令快速创建使用此库的示例项目:
> dotnet new -i Audit.WebApi.Template
> dotnet new webapiaudit
这件事发生在我身上。。。所以我真的很感激你的回答,它为我节省了很多时间。@k0stya你如何在你的
api
控制器中应用LoggingHandler
?链接失效,这里有一个回程链接我如何分析日志?在sharepoint中创建仪表板并定义kpi列表?这只是捕获用于记录的信息。如何/记录什么,甚至如何查看日志的细节则是另一回事。与此问题无关的一个问题。@JasonMeckley如何在api
控制器中使用LoggingHandler
?此实现旨在记录请求/响应。如果您需要控制器中的记录器,请将另一个记录器传递给控制器,关于如何实现这一点,有多种选项。