-
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
Add IAsyncEnumerable support to MVC #4833
Comments
Conneg isn't often used in new apps to choose between XML and JSON, it's used more frequently nowadays associate a data type with a media type. yeah that's not really content negotiation... But I digress, in general media types matter to developers and clients more than they did in the bad old days of XML or JSON 😆
The backpressure is the only hard part of this. IMO |
As long as we don't have to build that, I'm with you. Rx comes with throttling and all kinds of crazy observable combinators out of the box. We should play with them to see what users would need to do if they wanted this feature. I don't want us to build a scheduler implementation into MVC that handles back pressure when all we really need is a Task returned from OnNext 😄 (but I digress).
IEnumerable is an interesting one and it's very similar to what public class MyStreamingApi : Controller
{
[HttpGet("/tweets")]
[Streaming]
public async IAsyncEnumerable<Tweet> Get()
{
while (var tweet = await GetOneTweet())
{
yield return tweet;
}
}
} |
It seems like you're talking about what developers would want to write vs I'm talking about what we would have to do support it.
|
Yeah, that's what I found with SignalR exploration. We'd have to spin up a thread just to iterate the enumerable. |
Yep. This one has more detail though. |
Of course, so we need to close the other one |
So the intention of this to allow something such as an SSE Event Source to be implemented as a short lived action that returns an object which is then registered in a background service somewhere and has updates pushed to it? I currently have SSE implemented by writing to |
Yes
I think the heavy lifting would be on our side to build this. As long as we have something to Also this isn't either/or, we'd do both (assuming |
I'm new to ASP.NET Core, so excuse me if I'm stating something obvious... Have you considered exception handling for action methods implemented as iterators? The "prologue" (code path from the beginning of the method to the first For example:
You'd probably want this to fail immediately, not when the HTTP response has already started streaming to the Web browser. If ASP.NET Core starts iterating after it has already sent headers to the Web browser, there may not be a sensible way to handle any "prologue" exceptions that late. To remedy that, you could eagerly perform the iteration over the first element...
We currently use the above code under ASP.NET Core 1.1, to make handling database exceptions in our ADO.NET-based action methods more robust. Essentially, if the connection and query execution have passed without exception (this is our "prologue"), it is extremely unlikely we'll get any exception while fetching the rows. I'm wondering if something like above should be built-into ASP.NET Core, to avoid "gotchas" when users implement their action methods using |
@branko-d Can you file another issue for this? It's not exactly related to Streaming and there's already a standard way to eagerly evaluate an |
@davidfowl This is about eager evaluation of the fist iteration, not the entire sequence.
I don't know if you are aware of it, but databases routinely "stream" query results, i.e. they don't materialize the entire resultset in memory, but instead walk the indexes as the client fetches the rows. This is not always possible, obviously, but the DBMS will automatically do it when it is. Some DBMSes will even allow you to tell them whether query planner should optimize for that case (e.g. Oracle's FIRST_ROWS vs. ALL_ROWS query hint). Being able to implement an MVC action method via That being said, I'll happily create a new issue if you think it's better that way. :) |
@branko-d how well does that work without asynchrony? What does your controller actually look like? What you mention is very loosely related to streaming results to the client. Error handling is a good topic to elaborate on here but using |
@davidfowl We are not sure at this point. Our (admittedly very simplistic) initial tests suggest that asynchronous ADO.NET ( While I can understand why synchronous operation would be problematic on a typical Web site, we have a different load - relatively few, relatively "fat" clients (our system will work with Mechanical CAD data, with up to few hundred engineers accessing it). I would expect the database will become bottleneck long before middle tier thread exhaustion does, but we don't know for sure at this point. To answer your question, our action methods (will) look essentially like this (pseudocode):
What would be an asynchronous alternative to this, without having to materialize the entire resultset in memory? |
Hijack? The reversed distributed Rx-over-web scenario of a client pushing a (non-file-data) multipart stream to the WebApi (as an observer) would also be of significant benefit since this currently requires web-sockets or message-bus infastructures. I'm talking about simple data streams from a device, client initiated, being pushed to the server over a short time period, similar to an multi-part file upload. For example the server-side API corresponding to https://github.com/paulcbetts/refit multi-part uploads, or perhaps a simple Rx-Overloading of https://msdn.microsoft.com/en-us/library/system.net.http.multipartstreamprovider(v=vs.118).aspx which we are looking into. Or perhaps something exists already that we have missed? |
@PtwHub looking for something like this aspnet/SignalR#515? |
Indeed. This looks like a good fit. Thanks. Looking forward to it. |
Is there anything in asp.net core 2.0 what would allow to repeat PushStreamContent's functionality? |
This is trivial to do with MVC today, you can just write to the response body directly from the controller. |
@davidfowl will I be able to modify headers after I start writing to response body? |
No |
@rynowak, is this something we will do in 2.2? |
Move to 3.0 |
@davidfowl really doesn't want me to win the argument over |
@rynowak if it's any consolation I really want this feature and plan to convert it to a iobservable when using it if you don't do it here |
@cdebergh - if you're interesting trying something like this out, you would probably want to start by implementing a method that returns either Then implement an output formatter that iterates and processes each chunk as it's available - but the key is that |
IObserable is for multicast and doesn’t fit here well support IAsyncEnumerable and there’ll be a method to go from one to the other that will describe the policy to apply when backpressure needs to be applied. I’ll spar with @rynowak later 😆 |
Cool I'm looking forward to have a way to convert |
That’s the wrong way 😁 |
Looking forward to the right way! |
For 3.0, we're doing a fairly scoped change viz to add support for |
Edit: @rynowak hijacking top post for great justice
This would include adding support for returning
IAsyncEnumerable<>
from an action method and letting MVC do the buffering for you before giving the data to the formatter.This would require integrating with JsonResult and ObjectResult
The text was updated successfully, but these errors were encountered: