【问题标题】:AS.NET WEB API Global Exception Handler Cannot Access Request ContentAS.NET WEB API 全局异常处理程序无法访问请求内容
【发布时间】:2016-06-02 22:01:08
【问题描述】:

我正在尝试记录有关导致异常的请求的信息。

我正在尝试读取附加到下面的 ExceptionHandlerContext 的请求的内容:-

虽然我可以访问请求对象的其他部分,但它的内容总是空的。

目前看来,它已经在管道中被处理掉了。

有没有办法在堆栈中捕获这么远的请求正文?

public class GlobalExceptionHandler : ExceptionHandler
    {
        public override void Handle(ExceptionHandlerContext context)
        {
            var exception = context.Exception;

            var test = context.Request.Content.ReadAsByteArrayAsync().Result;

            var httpException = exception as HttpException;
            if (httpException != null)
            {
                context.Result = new ErrorResult(context.Request, (HttpStatusCode)httpException.GetHttpCode(), httpException.Message);
                return;
            }

            if (exception is BusinessRuleViolationException)
            {
                context.Result = new ErrorResult(context.Request, HttpStatusCode.PaymentRequired, exception.Message);
                return;
            }

            context.Result = new ErrorResult(context.Request, HttpStatusCode.InternalServerError, exception.Message);
        }
    }

【问题讨论】:

    标签: logging asp.net-web-api2


    【解决方案1】:

    对于以后发现这个话题的人来说,答案很简单,但隐藏得很好。

    首先,这里涉及到性能问题。

    在我找到更好的解决方案之前,我将使用以下方法。

    这里的问题是,当我们在管道中的某个点将其记录到我们的异常处理程序中时,Request.Content 属性已经被处理掉了。

    到目前为止,我发现的唯一解决方法是通过消息处理程序将此属性读入缓冲流。

    警告! - 我们正在将请求的正文提交到内存中。

    public class RequestBufferMessageHandler : DelegatingHandler
        {
            protected async  override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                await request.Content.LoadIntoBufferAsync();
    
                return await base.SendAsync(request, cancellationToken);
            }
        }
    

    注意:您可以使用您希望流式传输的内容的最大大小来重载此方法,因此如果请求中有一个大文件,它不会尝试将其提交到内存中。

    我们需要使用 HttpConfiguration 将其注册为消息处理程序,如下所示:-

    config.MessageHandlers.Add(new RequestBufferMessageHandler());
    

    现在,当我尝试在我的 ExceptionLogger 实现中访问请求正文时,我可以访问它:-

    public class CustomExceptionLogger : ExceptionLogger
        {
            private readonly ILog _log;
    
            public CustomExceptionLogger(ILogManager logManager)
            {
                _log = logManager.GetLog(typeof(CustomExceptionLogger));
            }
    
    
            public override async  Task LogAsync(ExceptionLoggerContext context, CancellationToken cancellationToken)
            {
                var body = await context.Request.Content.ReadAsStringAsync();
    
    
                var data = new
                {
    
                    requestUrl = context.Request.RequestUri,
                    requestQueryString = context.RequestContext.RouteData.Values,
                    requestMethod = context.Request.Method,
                    requestBody = body,
                    exception = context.Exception.Message
    
                };
    
                _log.Error(data);
    
            }
    
    
        }
    

    【讨论】:

    • 它对我帮助很大,但要注意,要为我工作,我必须替换 config.Services.Replace(typeof(IExceptionLogger), new CustomExceptionLogger());
    猜你喜欢
    • 1970-01-01
    • 2017-10-12
    • 2015-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-17
    • 2012-12-31
    • 2011-05-19
    相关资源
    最近更新 更多