-
Notifications
You must be signed in to change notification settings - Fork 25.1k
Update request-response.md #35289
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update request-response.md #35289
Conversation
| When writing directly to `HttpResponse.BodyWriter`, call `PipeWriter.FlushAsync()` manually to ensure the data is flushed to the underlying response stream. Here's why: | ||
|
|
||
| * `HttpResponse.BodyWriter` is a `PipeWriter` that buffers data until a flush operation is triggered. | ||
| * Calling `FlushAsync` writes the buffered data to the underlying Stream (`HttpResponse.Body`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we specify how frequently the FlushAsync should be called? Once? Once per Advance? Every X bytes advanced?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we specify how frequently the FlushAsync should be called? Once? Once per Advance? Every X bytes advanced?
My guess is it's hard to give a simple answer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My guess is it's hard to give a simple answer.
True. A generic rule when to call Flush is hard to impossible to give.
Very general:
- call
Flushto make the data available to thePipeReader(here: the response body), so that the response can be transmitted (chunked) over the wire to the client - call
Flushwhen someting is written that thePipeReadershould have access to (before completing the pipe)
But I don't know how to defer a rule out of the points.
Honestly, I'd just omit something like this, as at the end of the article there's a link to System.IO.Pipelines in .NET which has further infos.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we say something like "It's up to the developer to decide when to call FlushAsync, balancing factors such as buffer size, network write overhead, and whether the data should be sent in discrete chunks."
Co-authored-by: Günther Foidl <[email protected]>
|
@Rick-Anderson could you also cover what I mentioned in #35288 (comment) |
| * `HttpResponse.WriteAsync` | ||
|
|
||
| Streams aren't being removed from the framework. Streams continue to be used throughout .NET, and many stream types don't have pipe equivalents, such as `FileStreams` and `ResponseCompression`. | ||
| Streams aren't being removed from the framework. Streams continue to be used throughout .NET, and many stream types don't have pipe equivalents, such as `FileStreams` and `ResponseCompression`, and straightforward adding compression to the stream. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand that it is not possible to write a custom compression middleware with PipeWriter. Is that correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Rick-Anderson could you also cover what I mentioned in #35288 (comment)
That's what I tried to do here (line 28 change).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand that it is not possible to write a custom compression middleware with PipeWriter. Is that correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not possible to write a custom compression middleware with PipeWriter
It's possible, but very awkward compared to Streams. W/ Streams it's quite easy, as the decorator pattern can be used to wrap a stream, which wraps a streams, etc.
W/ PipeWriter more custom code would be needed. E.g. an intermediate Pipeline that reads what the user's PipeWriter writes (and flushes), then perfom the compression and write (and flush) it the response body's PipeReader.
Also for compression .NET provides no easy to use infrastructure for this use case.
So as said it's possible, but w/ quite an effort. So I see no reason why one should use PipeWriter for this, when it's quite easy to accomplish with Streams.
Note: The Stream in the response is quite a simple adapter for the PipeWriter (at least in Kestrel), so there shouldn't be any perf-difference, especially when the data is sent over the network. So use either Body or BodyWriter depending on the use case and on how it can be done more easily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Stream in the response is quite a simple adapter for the PipeWriter
I think this is the piece that I was missing. The pipe and stream are different APIs for the same channel of data? For example, if my endpoint middleware writes to pipe and my compression middleware wraps the stream, my data will be compressed?
Could we explicit this part in this document 🙏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pipe and stream are different APIs for the same channel of data?
Yep.
Underlying is the network socket, from which data is written / read. In oder to make these operations easier to use and abstracted away (because instead of network socket it could also be named pipes, unix domain sockets, etc. -- effort was done in ASP.NET Core with so called "project bedrock") there's pipes and streams, which allow "unified" access higher up in the stack.
if my endpoint middleware writes to pipe and my compression middleware wraps the stream, my data will be compressed?
W/o knowing your code I'm not able to say yes or no.
Interleaving PipeWriter and BodyStream is dangerous, as none of these is thread-safe. They're not intended to be used concurrent or mixed in any way.
So it really depends when you write / flush the pipe and what you'll do with the stream.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's say my endpoint handler is just writing a protobuf object to the pipe
MyProtoObject.WriteTo(HttpContext.Response.BodyWriter)and I use the standard response compression middleware
app.UseResponseCompression();I'm expecting the compression middleware to decorate the stream and not touch the pipe. I'm wondering if my response will be compressed.
gfoidl
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides the little suggestion LGTM.
Co-authored-by: Günther Foidl <[email protected]>
fixes #35288
@martincostello please review. The other questions are answered in the doc.
Internal previews