-
Notifications
You must be signed in to change notification settings - Fork 10.1k
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
Cannot implement TextOutputFormatter for IAsyncEnumerable<T> #23203
Comments
@manandre In your case, I think it is best if you create your own action result to handle streaming the response. I've dug a bit more into this and I've confirmed that the issue is that we don't have any knowledge about whether a formatter supports IAsyncEnumerable or not, so we are forced to buffer the results ahead of time to make sure it works with all formatters. I'm not sure if STJ will ever support this, but it will be very unlikely XML will support this at all. If STJ decides to support something like this, we might consider improving the support here, by adding a check/config that allows indicating a given formatter "supports" streaming and in that case avoid the buffering. We might need to adapt some things here, like the content length and so on too, since we won't know by the time we start writing the response. Buffering the asyncenumerable would be the default behavior unless we detect that the formatter we selected supports streaming. It is unlikely that we build something like this for 5.0, so I'm moving this issue to the backlog for future consideration if we hear more feedback about it. |
@javiercn Thanks for your quick, clear and complete answer about my issue. |
@manandre our initial plan was based on @javiercn's suggestion here:
dotnet/runtime#1570 is still scheduled for 5.0, so we might add support for this before this release. We'd also be open to a PR if you'd like to send one. public interface ISupportAsyncEnumerableOutputFormatter {} which |
In response to dotnet/runtime#1570, I made API proposal dotnet/runtime#38055. This proposes making System.Text.Json support There is in fact an implementation of this proposal in a PR but I committed a gaffe because I didn't know about the API review process and submitted my PR with no review. If the review of the proposal goes favourably, then the implementation should itself be immediately ready for review. Crossing fingers :-) |
This would specifically benefit S.T.J. MVC will continue buffering for all other formatters, which is why MVC needs a gesture that indicates when a formatter suppports serializing IAsyncEnumerable. |
Hmm, I wasn't aware that there was non-System.Text.Json buffering going on. The buffering that I knew about is very System.Text.Json-specific: |
Ahh, I see there's this too: Hmm |
Question, what is the reason that ASP.NET Core handles There's also a third advantage: If a route returns an |
The IAsyncEnumerable support in MVC specifically exists to avoid sync-over-async. We did not set out to implement full featured support for this since we expect some formatters to eventually support it.
There is an upper bound to the number of buffered elements: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.mvcoptions.maxiasyncenumerablebufferlimit?view=aspnetcore-3.1#Microsoft_AspNetCore_Mvc_MvcOptions_MaxIAsyncEnumerableBufferLimit |
Hmm, but by explicitly buffering the contents, isn't it even more sync-over-async than if it did a micro sync-over-async per element? |
I have become aware of the following scenario:
Thus, a deadlock arises. For the benefit of others reading this, so that they understand the context more fully: When ASP.NET Core is buffering the System.Text.Json is @pranavkm I have done further reading which brings me greater understanding of your earlier comments. Specifically, I see the distinction between result executors and output formatters, and notice that the result executors -- all of them, independently -- are where the This change, however, would only make sense after System.Text.Json supports |
## Description System.Text.Json recently added support for streaming IAsyncEnumerable types based on an ask from the ASP.NET Core team. This PR enables MVC to leverage this feature. ## Customer Impact Using IAsyncEnumerable with System.Text.Json will result in data to be streamed rather than buffered and serialized. ## Regression? - [ ] Yes - [x] No [If yes, specify the version the behavior has regressed from] ## Risk - [ ] High - [ ] Medium - [x] Low [Justify the selection above] The feature has been well-tested in the runtime. This is simply removing additional buffering that was previously performed by MVC before invoking the serializer. ## Verification - [x] Manual (required) - [x] Automated ## Packaging changes reviewed? - [ ] Yes - [x] No - [ ] N/A Addresses #11558 #23203
@manandre starting in 6.0-preview4, MVC makes supporting up to individual formatters to handle |
@pranavkm Thanks for such a quick implementation on aspnetcore side. I will be able to replace my horrible workarounds in such a perf-critical place 👍 |
Issue description
I have created a custom implementation of the TextOutputFormatter to stream
IAsyncEnumerable<T>
outputs in the response body in my custom (TSV) format. But, at runtime theCanWriteType
method only receives aList<T>
type, what is not expected and prevents any streaming operation :/To Reproduce
The repro project (https://github.com/manandre/asyncenumerable-outputformatter-issue) is based on a swagger Pet sample, modified to return the list of Pets as an
IAsyncEnumerable<Pet>
collection.A custom
TsvOutputFormatter
is added to illustrate the issue (as a debug assert).Further technical details
dotnet --info
The text was updated successfully, but these errors were encountered: