Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get request body in web api IExceptionHandler

I'm trying to write a global error handler for ASP.NET web api that is able to log the request details of requests that cause unhandled exception in my api. I've registered the below GlobalExceptionHandler class in my OWIN startup class, but I'm unable to retrieve the content of any data posted in the body of requests.

public class GlobalExecptionHander : ExceptionHandler
{
    public override void Handle(ExceptionHandlerContext context)
    {
        var body = context.Request.Content.ReadAsStringAsync().Result;
        //body here is an empty string

        context.Result = new UnhandledErrorActionResult
        {
            Request = context.Request,
        };
    }
}

In my startup class

config.Services.Replace(typeof(IExceptionHandler), new GlobalExecptionHander());
like image 671
Dav Evans Avatar asked Nov 09 '22 02:11

Dav Evans


1 Answers

Since I just came across this exact problem, I was amazed to find this question without an answer! I hope you've managed to solve the problem after all this time. I'd still like to answer this question regardless.

The thing is that by the time your GlobalExceptionHandler handles the exception, something (like Newtonsoft Json or any other request handler) has already read the contentstream of the HTTP request. When the stream is read, you cannot read it again, unless there was some way to reset that stream to its initial position...

public override void Handle(ExceptionHandlerContext context)
{
    string requestContent = "";
    using(System.IO.Stream stream = context.Request.Content.ReadAsStreamAsync().Result)
    {
        // Set the stream back to position 0...
        if (stream.CanSeek)
        {
            stream.Position = 0;
        }

        // ... and read the content once again!
        requestContent = context.Request.Content.ReadAsStringAsync().Result;
    }

    /* ..Rest of code handling the Exception.. */
}

The reason requestContent is outside that using block, is because the stream gets disposed after the block closes. You could also get rid of using and call stream.Dispose() after you've done reading the content.

like image 127
Baksteen Avatar answered Nov 14 '22 21:11

Baksteen