Reading the request body in middleware leaves handlers with an empty body
Reading the request body in logging middleware can leave the endpoint handler and model binding with an empty body. The author reproduces the problem with a 61-byte JSON POST and shows how EnableBuffering plus a position reset fixes it. A pitfall every ASP.NET Core developer who logs payloads should know.
Key points
- After middleware reads the body, the handler can see an empty stream, and model binding then fails with null models or missing-field errors.
- Fix: call context.Request.EnableBuffering() before the first read.
- Reset context.Request.Body.Position to 0 after reading; EnableBuffering alone does not rewind the stream.
- The default in-memory threshold is about 30 KB, after which the body spills to a temporary file on disk.
- Where possible, log the size or a hash instead of the raw payload, and enable buffering only on routes that need it.
When request-body logging was added to an API, POST endpoints began rejecting valid orders with validation errors. The cause is that the request body is a forward-only stream: once middleware reads it to the end, the handler finds nothing left. The author reproduced this with a minimal app, where the middleware read 61 bytes and the handler read zero, without any error on the handler's side.
The fix is HttpRequest.EnableBuffering(), which makes the stream seekable, followed by resetting Body.Position to zero after the read. Buffering has a cost: bodies are kept in memory until they pass a threshold, around 30 KB by default, and then spill to a temporary file. The author advises avoiding raw body reads in middleware, logging a size or hash instead, and enabling buffering only on routes that truly need it.
Real-world use
- Logging POST bodies for audit in an order API without breaking model binding in the endpoint.
- Verifying a webhook signature by reading the raw body in middleware and then parsing it again in the handler.
- Enabling body buffering only on selected routes in an API that also accepts large uploads.
Why it matters
Any code that reads the body in middleware can silently starve later consumers. Knowing this avoids production bugs that look like valid requests being rejected.