我使用this blog post中的详细信息构建了一个记录DelegatingHandler
的请求。
我不想阅读请求或响应机构(这项工作在可能的高容量Web服务上看起来很愚蠢);我想要做的就是为每个请求分配一个唯一的ID,记录URI和标题;将请求ID写入另一个头中的响应,然后记录响应(成功/失败)和发生的任何异常。
protected override System.Threading.Tasks.Task<HttpResponseMessage>
SendAsync(HttpRequestMessage request,
System.Threading.CancellationToken cancellationToken)
{
DateTime receivedUTC = DateTime.UtcNow;
//I use the Request properties to persist a Request's ID
var requestID = request.GetRequestUID();
if (requestID == null)
requestID = request.SetRequestUID();
//grab the base response task
var baseResult = base.SendAsync(request, cancellationToken);
return baseResult.ContinueWith(innerTask =>
{
var tcs = new TaskCompletionSource<HttpResponseMessage>();
//note I've got rid of SynchronizationContext code out of this
//to keep it shorter
//construct the log packet
LogData toLog = new LogData()
{
ReceivedUTC = receivedUTC,
Request = request,
RequestID = requestID,
};
//get the response
try
{
tcs.SetResult(innerTask.Result);
//NOTE - If this request actually fails response serialization,
// Then the above result will actually look fine, because
// The error hasn't occurred yet!
toLog.Response = innerTask.Result;
//this adds a header
AddRequestIDToResponse(toLog.Response, requestID);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
toLog.Ex = ex;
}
//fire the logging call asynchronously (code elided, just some DB work)
Task.Factory.StartNew(() => Log(toLog));
return tcs.Task;
}).Unwrap();
}
除了从动作方法返回的ObjectContent
被序列化为响应时发生异常时,这几乎对所有请求都完全正常。
如果发生这种情况,上面的代码已经触发了,它在上面的try / catch块中看到的响应消息显示为普通200
,ObjectContent
包含最终会失败的对象序列化。这确实有意义 - 因为尚未发生对响应主体的序列化。
如何更改此代码(不强制读取ObjectContent
)以确保我看到的响应消息是 实际 消息客户端收到内容格式化后?我应该看一个不同的可扩展性点吗?
答案 0 :(得分:3)
作为一个试探性的答案,直到有人(希望)出现并证明我错了;在没有复制和粘贴大量代码的情况下,Web API管道本身似乎无法实现这一点。
内容序列化在Web API管道的最顶层触发 - 在HttpControllerHandler
中,HttpContent
被复制到基础HttpResponse
的{{1}}在一个名为OutputStream
的内部静态方法中。类本身没有足够的可扩展点,无法在正确的位置注入任务,以便能够在Web API管道中记录实际的响应。
所以我面对的是:
从源头完整地提升HttpControllerHandler.ConvertResponse
代码并将其导入我的项目(以及它使用的所有内部,
这不是一个好主意,然后相应地定制它。
只是提前强制序列化并捕获异常 - 我可以记录
例外但不是回应。有一个小问题
尽管如此 - 将请求ID写入响应是非常的
很重要,当发生这些格式化异常时,ID不会
写作是因为HttpControllerHandler
取代了整个
响应它的错误响应!
从Web API向上一级记录请求。这
并不理想,因为我只想记录 Web API 请求;和
日志代码也依赖于当前请求的
HttpConfiguration对象以获取特定于请求的DI
用于解析数据库连接的容器(它是一个多租户Web
服务)。
最终唯一真正的选择是最后一个 - 在IIS或Asp.Net级别完成工作。因此,尽管Web API中存在所有这些可扩展性点 - 您实际上无法在其中实现“完整”的日志记录解决方案 - 这真的令人失望。