Write the HTTP response only when all output has been formatted#858
Conversation
|
This might resolve: #704 |
|
@microsoft-github-policy-service agree |
| } | ||
|
|
||
| await serializer.WriteObjectAsync(value, type, messageWriter, writeContext).ConfigureAwait(false); | ||
| await request.HttpContext.Response.Body.WriteAsync(responseBody.ToArray()); |
There was a problem hiding this comment.
do we really need to create array of unknown size here?
There was a problem hiding this comment.
i used responseBody.CopyTo(request.HttpContext.Response.Body) initially, but it didn't work how I expected so I resorted to this. I'll find a better way
There was a problem hiding this comment.
Ha, I was missing rewinding the buffer response body stream back to position zero
| ODataPath path = request.ODataFeature().Path; | ||
| IEdmNavigationSource targetNavigationSource = path.GetNavigationSource(); | ||
| HttpResponse response = request.HttpContext.Response; | ||
| var responseBody = new MemoryStream(); |
There was a problem hiding this comment.
Do you mean Microsoft.IO.RecyclableMemoryStream ?
There was a problem hiding this comment.
@wedgberto -- thanks for your contribution!
Note that we do not want to buffer in memory by default -- this can have a significant performance impact for large responses, and we do everything possible to make sure that we are able to stream a response without buffering.
In order to support efficient streaming, the OData protocol specifically describes instream error scenarios, calling for the response body to be malformed JSON.
So rather than return an appropriate HTTP error status code, the spec states to return a 200 OK with a malformed JSON response body. If that is the case then I guess this PR is obsolete and can be aborted. We'll just have to code our Angular consumer to compensate and not assume that 200 OK responses contain valid JSON. There are other issues in this repo that mention incomplete JSON in the response that might find this specified behaviour useful. #760 #219 #109 |
| @@ -21,6 +21,7 @@ | |||
| using Microsoft.AspNetCore.OData.Formatter.Value; | |||
There was a problem hiding this comment.
Could we add a test for this functionality ?
Purpose
This PR "buffers" the OData message wrapper in a memory stream until the OData query has been enumerated, then copies it into the HTTP response body only when no exception has been thrown.
Scenario
A WebAPI endpoint is serviced by an Entity Framework 6.0 IQueryable.
When the SQL query is executed but the configured SQL command timeout is exceeded, our exception handling middleware successfully catches the SqlException, but is unable to set the HTTP status code to 500 because the HTTP response body is already started.
The endpoint returns a 200 OK HTTP status code and a body containing malformed JSON: