C# 捕获DelegatingHandler中的ObjectContent序列化错误,而不读取响应

C# 捕获DelegatingHandler中的ObjectContent序列化错误,而不读取响应,c#,asp.net-mvc-4,asp.net-web-api,C#,Asp.net Mvc 4,Asp.net Web Api,我使用中的详细信息构建了一个请求日志DelegatingHandler 我不想阅读请求或响应机构(在一个潜在的高容量web服务上,将此工作加倍似乎很愚蠢);我只想为每个请求分配一个唯一的ID,记录URI和头;将请求ID写入另一个标头中的响应,然后记录响应(成功/失败)和发生的任何异常 protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage r

我使用中的详细信息构建了一个请求日志
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();
}
protected override System.Threading.Tasks.Task
SendAsync(HttpRequestMessage请求,
System.Threading.CancellationToken CancellationToken)
{
DateTime receivedUTC=DateTime.UtcNow;
//我使用请求属性来持久化请求的ID
var requestID=request.GetRequestUID();
if(requestID==null)
requestID=request.SetRequestUID();
//抓取基本响应任务
var baseResult=base.sendaync(请求、取消令牌);
返回baseResult.ContinueWith(innerTask=>
{
var tcs=new TaskCompletionSource();
//注意,我已经去掉了SynchronizationContext代码
//缩短
//构造日志包
LogData toLog=新的LogData()
{
ReceivedUTC=ReceivedUTC,
请求=请求,
RequestID=RequestID,
};
//得到回应
尝试
{
SetResult(innerTask.Result);
//注意-如果此请求实际上未能通过响应序列化,
//那么上面的结果实际上看起来不错,因为
//错误还没有发生!
toLog.Response=innerTask.Result;
//这将添加一个标题
AddRequestIDToResponse(toLog.Response,requestID);
}
捕获(例外情况除外)
{
tSystexception(ex);
toLog.Ex=Ex;
}
//异步触发日志调用(代码省略,只是一些数据库工作)
Task.Factory.StartNew(()=>Log(toLog));
返回tcs.Task;
}).Unwrap();
}
这一切对于几乎所有的请求都绝对有效,除非从操作方法返回的
ObjectContent
序列化到响应时发生异常

如果发生这种情况,则上述代码已经触发,并且它在上面的try/catch块中看到的响应消息显示为正常的
200
,其中
ObjectContent
包含最终将无法序列化的对象。这是有道理的,因为对响应体的序列化还没有发生


如何更改此代码(无需强制读取
ObjectContent
),以确保在内容格式化后,我看到的响应消息是客户端收到的实际消息?我应该考虑另一个扩展点吗?

作为一个试探性的答案,直到有人(希望)证明我错了;如果不复制和粘贴大量代码,这在WebAPI管道本身中似乎几乎是不可能的

内容序列化在Web API管道的最顶端触发-在
HttpControllerHandler
中,其中
HttpContent
通过名为
HttpControllerHandler.ConvertResponse
的内部静态方法复制到底层
HttpResponse
OutputStream
。类本身没有足够的扩展点,无法在正确的位置注入任务,从而能够在Web API管道中记录实际响应

因此,我面临着:

  • 从源代码整体提升HttpControllerHandler 编码并将其导入到我的项目中(以及它使用的所有内部构件, 这不是一个好主意),然后相应地定制它

  • 只要尽早强制序列化并捕获异常,我就可以记录 异常,但不是响应。
    不过,将请求ID写入响应非常困难
    重要信息,当出现这些格式异常时,ID不会 因为
    HttpControllerHandler
    替换了整个
    用它的错误响应进行响应

  • 从Web API向上记录下一级的请求。这
    不是很理想,因为我只想记录Web API请求;和
    日志代码还依赖于当前请求的
    HttpConfiguration对象以获取特定于请求的DI
    用于解析数据库连接(它是一个多租户web)的容器 服务)


最终,唯一真正的选择是最后一个——在IIS或Asp.Net级别执行工作。因此,尽管Web API中存在所有这些可扩展性点,但实际上您无法在其中实现“完整”的日志解决方案,这确实令人失望。

作为一个试探性的答案,直到有人(希望)出现并证明我错了;如果不复制和粘贴大量代码,这在WebAPI管道本身中似乎几乎是不可能的

内容序列化在Web API管道的最顶端触发-在
HttpControllerHandler
中,其中
HttpContent
通过名为
HttpControllerHandler.ConvertResponse
的内部静态方法复制到底层
HttpResponse
OutputStream
。类本身没有足够的扩展点,无法在正确的位置注入任务,从而能够在Web API管道中记录实际响应

因此,我面临着:

  • 从源代码整体提升HttpControllerHandler 编码并将其导入到我的项目中(以及它使用的所有内部构件, 这不是一个好主意),然后相应地定制它

  • 只要尽早强制序列化并捕获异常,我就可以记录 例外情况,但不包括re