AS.NET WEB API Global Exception Handler Cannot Acc

2019-07-19 06:45发布

I'm trying to log information about the request that has caused an exception.

I'm trying to read the Content of the request attached to the ExceptionHandlerContext below :-

Although I can access other parts of the request object, its content is always empty.

It seems by this point in the pipeline it has been disposed.

Is there a way to capture the request body this far up the stack?

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);
        }
    }

1条回答
We Are One
2楼-- · 2019-07-19 07:08

For anyone that finds this thread in the future, the answer is quite simple but well hidden.

Firstly, there is a performance concern involved here.

Until i find a better solution i will be going with the following method.

The problem here is that the Request.Content property has been disposed of by the time we are at a point in the pipeline to log it in our exception handler.

The only workaround i have found so far is to read this property into a bufferstream via a message handler.

WARNINING! - We are commiting the body of the request to memory.

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

            return await base.SendAsync(request, cancellationToken);
        }
    }

Note: You can overload this method with the maximum size of the content you wish to stream, so if there is a large file in the request it will not attempt to commit it to memory.

We need to register this as a message handler with HttpConfiguration as follows :-

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

Now, I am able to access the requests body when i try to access it in my ExceptionLogger implementation :-

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);

        }


    }
查看更多
登录 后发表回答