It seems that AspNet.Core starts sending response that is IEnumerable
right away without iterating over the whole collection. E.g.:
[HttpGet("")]
public async Task<IActionResult> GetData()
{
IEnumerable<MyData> result = await _service.GetData();
return Ok(result.Select(_mapper.MapMyDataToMyDataWeb));
}
Now there is an exception that happens during mapping of one of the elements, so I would assume a 500
response, but in reality what happens is that I get a 200
with only partial (and incorrect) Json.
I assume it's a feature and not a bug in Asp.Net Core
that provides this behavior and it is additionally relatively easy to fix by calling e.g. ToList()
, but I am wondering if there is some kind of flag that can prevent this situation from happening since it does not really make sense for e.g. API project and standard JSON response.
I was not able to find anything in documentation that describes this behavior and how to prevent it.
P.S. I have verified that calling ToList()
fixes the issue and the response is 500 with correct exception (with UseDeveloperExceptionPage
)
If a controller action returns any IEnumerable that has not been realized yet, and an exception happens during evaluation of it, a 200 response is returned with invalid JSON. It is arguable that controller methods should not return an unrealized IEnumerable in the first place, but there's nothing stopping you.
Use the UseExceptionHandler middleware in ASP.NET Core So, to implement the global exception handler, we can use the benefits of the ASP.NET Core build-in Middleware. A middleware is indicated as a software component inserted into the request processing pipeline which handles the requests and responses.
It seems that this is actually "by design", this issue was raised few times on Asp.Net Core github repository.
What happens is that header with 200 is already sent, while the body is not. While I would think that enumeration must proceed before sending headers, asp.net team says it will use more resources on the server and that's why it is like that.
Here is a quote:
It is very likely the case that your exception is thrown while writing to the body, after headers have already been sent to the client, so there's no take-backs on the 200 that was already sent as part of the response. The client will see an error because the body will come back as incomplete.
If you want to deterministically report a 500 when this happens you'll need to either:
- Buffer your IEnumerable as part of the action (.ToList())
- Buffer the response body -https://github.com/aspnet/BasicMiddleware/tree/dev/src/Microsoft.AspNetCore.Buffering Obviously both of these things require more server-side resources, which is why we don't have this kind of behavior by default.
I can confirm that this solution worked:
Microsoft.AspNetCore.Buffering
packageapp.UseResponseBuffering()
before app.UseMvc()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With