I have an AspNet.Core.Mvc REST API that is routed through a proxy gateway. The gateway has a limit of 10mb for the response body. If the body is over that threshold it returns 500 Internal Server Error.
My goal: To check the size of the response body before returning from my API project and if it is over that threshold, return a BadRequest error instead, with a helpful error message in the response body content. Something like, "The response is too large. Try narrowing your request."
I've tried handling this in middleware, where the byte size of the body is known, but this is too late and the framework prevents this. I've tried working around this, something like this where you swap out the Body temporarily with a MemoryStream:
However, the status code is already set to 200 at that point and the framework throws an error if you try to change it. Here is the code snippet from the middleware where it copies the new response stream to the original body:
// Replace the body with a BadRequest error notifying user that the response
// was too large and they should narrow down their search parameters.
var errorStream = new MemoryStream();
var sw = new StreamWriter(errorStream);
sw.Write("Response exceeds maximum size. Try narrowing request parameters or setting a smaller page size if applicable.");
sw.Flush();
errorStream.Position = 0;
await errorStream.CopyToAsync(originalBody);
httpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; // throws exception!
I've also tried to handle it in the Controller method itself before returning, by serializing the response content to json, then converting the json string to bytes to check the size:
string json = JsonConvert.SerializeObject(value, jsonSerializerSettings);
byte[] bytes = Encoding.UTF8.GetBytes(json);
But that is all work that the framework will do for me, and seems wasteful (and frankly ugly). Is there a way to set this as the response and return it from the Controller? Maybe I can create a base class for the Controller that all API methods can use that will do this logic?
This all seems like a lot of trouble for something seemingly simple. I'm hoping someone here has a better solution.
value? It's far better to check the size of the returned data before serialization. If you return rows from a query, you can use aTOPin SQL orTakein LINQ to limit the results from the start.